题组1

79 阅读7分钟

题目一

给定一个有序数组arr,代表坐落在X轴上的点

给定一个正数K,代表绳子的长度

返回绳子最多压中几个点?

即使绳子边缘处盖住点也算盖住

public static int maxPoint2(int[] arr, int L) {
   int left = 0;
   int right = 0;
   int N = arr.length;
   int max = 0;
   while (left < N) {
      while (right < N && arr[right] - arr[left] <= L) {
         right++;
      }
      max = Math.max(max, right - (left++));
   }
   return max;
}

题目二

给定一个文件目录的路径,

写一个函数统计这个目录下所有的文件数量并返回

隐藏文件也算,但是文件夹不算

// 注意这个函数也会统计隐藏文件
public static int getFileNumber(String folderPath) {
   File root = new File(folderPath);
   if (!root.isDirectory() && !root.isFile()) {
      return 0;
   }
   if (root.isFile()) {
      return 1;
   }
   Stack<File> stack = new Stack<>();
   stack.add(root);
   int files = 0;
   while (!stack.isEmpty()) {
      File folder = stack.pop();
      for (File next : folder.listFiles()) {
         if (next.isFile()) {
            files++;
         }
         if (next.isDirectory()) {
            stack.push(next);
         }
      }
   }
   return files;
}

题目三

给定一个非负整数num,

如何不用循环语句,

返回>=num,并且离num最近的,2的某次方

public static final int tableSizeFor(int n) {
   n--;
   n |= n >>> 1;
   n |= n >>> 2;
   n |= n >>> 4;
   n |= n >>> 8;
   n |= n >>> 16;
   return (n < 0) ? 1 : n + 1;
}

题目四

一个数组中只有两种字符'G'和’B’,

可以让所有的G都放在左侧,所有的B都放在右侧

或者可以让所有的G都放在右侧,所有的B都放在左侧

但是只能在相邻字符之间进行交换操作,

返回至少需要交换几次

public static int minSteps2(String s) {
   if (s == null || s.equals("")) {
      return 0;
   }
   char[] str = s.toCharArray();
   int step1 = 0;
   int step2 = 0;
   int gi = 0;
   int bi = 0;
   for (int i = 0; i < str.length; i++) {
      if (str[i] == 'G') { // 当前的G,去左边   方案1
         step1 += i - (gi++);
      } else {// 当前的B,去左边   方案2
         step2 += i - (bi++);
      }
   }
   return Math.min(step1, step2);
}

题目五

leetcode.cn/problems/lo…

给定一个二维数组matrix,

你可以从任何位置出发,走向上下左右四个方向

返回能走出来的最长的递增链长度

public static int longestIncreasingPath1(int[][] matrix) {
   int ans = 0;
   int N = matrix.length;
   int M = matrix[0].length;
   for (int i = 0; i < N; i++) {
      for (int j = 0; j < M; j++) {
         ans = Math.max(ans, process1(matrix, i, j));
      }
   }
   return ans;
}

// 从m[i][j]开始走,走出来的最长递增链,返回!
public static int process1(int[][] m, int i, int j) {
   int up = i > 0 && m[i][j] < m[i - 1][j] ? process1(m, i - 1, j) : 0;
   int down = i < (m.length - 1) && m[i][j] < m[i + 1][j] ? process1(m, i + 1, j) : 0;
   int left = j > 0 && m[i][j] < m[i][j - 1] ? process1(m, i, j - 1) : 0;
   int right = j < (m[0].length - 1) && m[i][j] < m[i][j + 1] ? process1(m, i, j + 1) : 0;
   return Math.max(Math.max(up, down), Math.max(left, right)) + 1;
}

public static int longestIncreasingPath2(int[][] matrix) {
   int ans = 0;
   int N = matrix.length;
   int M = matrix[0].length;
   int[][] dp = new int[N][M];
   for (int i = 0; i < N; i++) {
      for (int j = 0; j < M; j++) {
         ans = Math.max(ans, process2(matrix, i, j, dp));
      }
   }
   return ans;
}

// 从m[i][j]开始走,走出来的最长递增链,返回!
public static int process2(int[][] m, int i, int j, int[][] dp) {
   if (dp[i][j] != 0) {
      return dp[i][j];
   }
   // (i,j)不越界
   int up = i > 0 && m[i][j] < m[i - 1][j] ? process2(m, i - 1, j, dp) : 0;
   int down = i < (m.length - 1) && m[i][j] < m[i + 1][j] ? process2(m, i + 1, j, dp) : 0;
   int left = j > 0 && m[i][j] < m[i][j - 1] ? process2(m, i, j - 1, dp) : 0;
   int right = j < (m[0].length - 1) && m[i][j] < m[i][j + 1] ? process2(m, i, j + 1, dp) : 0;
   int ans = Math.max(Math.max(up, down), Math.max(left, right)) + 1;
   dp[i][j] = ans;
   return ans;
}

题目六

给定两个非负数组x和hp,长度都是N,再给定一个正数range

x有序,x[i]表示i号怪兽在x轴上的位置;hp[i]表示i号怪兽的血量

再给定一个正数range,表示如果法师释放技能的范围长度

被打到的每只怪兽损失1点血量。

返回要把所有怪兽血量清空,至少需要释放多少次AOE技能?

public static int minAoe3(int[] x, int[] hp, int range) {
   int N = x.length;
   // coverLeft[i]:如果以i为中心点放技能,左侧能影响到哪,下标从1开始,不从0开始
   // coverRight[i]:如果以i为中心点放技能,右侧能影响到哪,下标从1开始,不从0开始
   // coverLeft和coverRight数组,0位置弃而不用
   // 举个例子,比如 :
   // x = [1,2,5,7,9,12,15], range = 3
   // 下标: 1 2 3 4 5 6 7
   // 以1位置做中心点: 能覆盖位置:1,2 -> [1..2]
   // 以2位置做中心点: 能覆盖位置:1,2,3 -> [1..3]
   // 以3位置做中心点: 能覆盖位置:2,3,4 -> [2..4]
   // 以4位置做中心点: 能覆盖位置:3,4,5 -> [3..5]
   // 以5位置做中心点: 能覆盖位置:4,5,6 -> [4..6]
   // 以6位置做中心点: 能覆盖位置:5,6,7 -> [5..7]
   // 以7位置做中心点: 能覆盖位置:6,7 -> [6..7]
   // 可以看出如果从左往右,依次求每个位置的左边界(left)和左边界(right),是可以不回退的!
   int[] coverLeft = new int[N + 1];
   int[] coverRight = new int[N + 1];
   int left = 0;
   int right = 0;
   // 从左往右,不回退的依次求每个位置的左边界(left)和左边界(right),记录到coverLeft和coverRight里
   for (int i = 0; i < N; i++) {
      while (x[i] - x[left] > range) {
         left++;
      }
      while (right < N && x[right] - x[i] <= range) {
         right++;
      }
      coverLeft[i + 1] = left + 1;
      coverRight[i + 1] = right;
   }
   // best[i]: 如果i是最左边缘点,选哪个点做技能中心点最好,下标从1开始,不从0开始
   // 与上面同理,依然可以不回退
   int[] best = new int[N + 1];
   int trigger = 0;
   for (int i = 0; i < N; i++) {
      while (trigger < N && x[trigger] - x[i] <= range) {
         trigger++;
      }
      best[i + 1] = trigger;
   }
   SegmentTree st = new SegmentTree(hp);
   st.build(1, N, 1);
   int ans = 0;
   // 整体思路:
   // 当前左边缘点从i位置开始(注意0位置已经弃而不用了),
   // 目标是把左边缘的怪物杀死,但是放技能的位置当然是尽可能远离左边缘点,但是又保证能覆盖住
   // best[i] : 放技能的位置当然是尽可能远离左边缘点i,但是又保证能覆盖住,
   // 请问这个中心在哪?就是best的含义,之前求过了。
   // 然后在这个中心点,放技能,放几次技能呢?左边缘点还剩多少血,就放几次技能,
   // 这样能保证刚好杀死左边缘点。
   // 然后向右继续寻找下一个没有死的左边缘点。
   for (int i = 1; i <= N; i++) {
      // 查询当前i位置,还有没有怪物存活
      long leftEdge = st.query(i, i, 1, N, 1);
      // 如果还有血量(leftEdge > 0),说明有存活。此时,放技能
      // 如果没有血了(leftEdge <= 0),说明当前边缘点不需要考虑了,换下一个i
      if (leftEdge > 0) {
         // t = best[i]: 在哪放技能最值
         // l = coverLeft[t]: 如果在t放技能的话,左边界影响到哪
         // r = coverRight[t]: 如果在t放技能的话,右边界影响到哪
         // 就在t放技能,放leftEdge次,这样左边缘点恰好被杀死
         ans += leftEdge;
         int t = best[i];
         int l = coverLeft[t];
         int r = coverRight[t];
         // 同时[l...r]整个范围,所有的怪物都会扣除掉leftEdge的血量,因为AOE嘛!
         st.add(l, r, (int) (-leftEdge), 1, N, 1);
      }
   }
   return ans;
}

题目七

leetcode.cn/problems/ta…

给定一个数组arr,你可以在每个数字之前决定+或者-

但是必须所有数字都参与

再给定一个数target,请问最后算出target的方法数是多少?

public static int findTargetSumWays1(int[] arr, int s) {
   return process1(arr, 0, s);
}

// 可以自由使用arr[index....]所有的数字!
// 搞出rest这个数,方法数是多少?返回
// index == 7 rest = 13
// map "7_13" 256
public static int process1(int[] arr, int index, int rest) {
   if (index == arr.length) { // 没数了!
      return rest == 0 ? 1 : 0;
   }
   // 还有数!arr[index] arr[index+1 ... ]
   return process1(arr, index + 1, rest - arr[index]) + process1(arr, index + 1, rest + arr[index]);
}

public static int findTargetSumWays2(int[] arr, int s) {
   return process2(arr, 0, s, new HashMap<>());
}

public static int process2(int[] arr, int index, int rest, HashMap<Integer, HashMap<Integer, Integer>> dp) {
   if (dp.containsKey(index) && dp.get(index).containsKey(rest)) {
      return dp.get(index).get(rest);
   }
   // 否则,没命中!
   int ans = 0;
   if (index == arr.length) {
      ans = rest == 0 ? 1 : 0;
   } else {
      ans = process2(arr, index + 1, rest - arr[index], dp) + process2(arr, index + 1, rest + arr[index], dp);
   }
   if (!dp.containsKey(index)) {
      dp.put(index, new HashMap<>());
   }
   dp.get(index).put(rest, ans);
   return ans;
}