线性表相关算法题
给定一个有序数组arr,代表坐落在X轴上的点,给定一个正数K,代表绳子的长度,返回绳子最多压中几个点,即使绳子边缘处盖住点也算盖住?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public int maxCoveredPoint(int[] arr, int K) { int maxValue = Integer.MIN_VALUE; int r = 0; for (int l = 0; l < arr.length; l++) { while (r < arr.length) { if (arr[r] - arr[l] > K) { break; } maxValue = Math.max(r - l + 1, maxValue); r ++; } } return maxValue; }
|
给定一个文件目录的路径,写一个函数统计这个目录下所有的文件数量并返回,隐藏文件也算,但是文件夹不算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public int getFileNumber(String path) { File root = new File(path); if (!root.exists()) { return 0; } if (!root.isDirectory() && !root.isFile()) { return 0; } if (root.isFile()) { return 1; } Stack<File> stack = new Stack<>(); stack.add(root); int fileNum = 0; while (!stack.isEmpty()) { File top = stack.pop(); for (File next : Objects.requireNonNull(top.listFiles())) { if (next.isFile()) { fileNum ++; } if (next.isDirectory()) { stack.push(next); } } } return fileNum; }
|
给定数组hard和money,长度都为N,hard[i]表示i号工作的难度,
money[i]表示i号工作的收入
给定数组ability,长度都为M,ability[j]表示j号人的能力,每一号工作,都可以提供无数的岗位,难度和收入都一样
但是人的能力必须>=这份工作的难度,才能上班。返回一个长度为M的数组ans,ans[j]表示j号人能获得的最好收入
有序表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public int[] bestJob(int[] hard, int[] money, int[] ability) { Job[] jobList = new Job[hard.length]; for (int i = 0; i < hard.length; i++) { jobList[i] = new Job(hard[i], money[i]); } Arrays.sort(jobList); TreeMap<Integer, Integer> treeMap = new TreeMap<>(); treeMap.put(jobList[0].hard, jobList[0].money); Job base = jobList[0]; for (int i = 1; i < jobList.length; i++) { if (jobList[i].hard > base.hard && jobList[i].money > base.money) { treeMap.put(jobList[i].hard, jobList[i].money); base = jobList[i]; } } int[] ans = new int[ability.length]; for (int i = 0; i < ability.length; i++) { Integer key = treeMap.floorKey(ability[i]); ans[i] = key != null ? treeMap.get(key) : 0; } return ans; }
static class Job implements Comparable<Job> { public int hard; public int money; public Job(int hard, int money) { this.hard = hard; this.money = money; }
@Override public int compareTo(Job o) { return this.hard - o.hard != 0 ? this.hard - o.hard : - this.money + o.money; }
@Override public String toString() { return "Job{" + "hard=" + hard + ", money=" + money + '}'; } }
|
给定一个数组arr,只能对arr中的一个子数组排序,但是想让arr整体都有序,返回满足这一设定的子数组中最短的是多长
https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public int minSortLength(int[] arr) { if (arr == null || arr.length < 2) { return 0; } int left = 0; int right = arr.length - 1; int max = Integer.MIN_VALUE; for (int i = 0; i < arr.length; i++) { if (arr[i] < max) { left = i; } max = Math.max(max, arr[i]); } int min = Integer.MAX_VALUE; for (int i = arr.length-1; i >= 0 ; i--) { if (arr[i] > min) { right = i; } min = Math.min(min, arr[i]); } return Math.max(0, left - right + 1); }
|
给定一个二维数组matrix,你可以从任何位置出发,走向上、下、左、右四个方向,返回能走出来的最长的递增链长度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public int longestIncreasingPath(int[][] arr) { int ans = 0; int N = arr.length; int M = arr[0].length; int[][] cache = new int[N][M]; for (int i = 0; i < N; i++) { for (int j = 0; j < M; j++) { ans = Math.max(ans, process(arr, i, j, cache)); } } return ans; }
private int process(int[][] arr, int i, int j, int[][] cache) { if (cache[i][j] != 0) { return cache[i][j]; } int up = 0, down = 0, left = 0, right = 0; if (i > 0 && arr[i][j] < arr[i-1][j]) { up = process(arr, i - 1, j, cache); } if (i + 1 < arr.length && arr[i][j] < arr[i+1][j]) { down = process(arr, i + 1, j, cache); } if (j > 0 && arr[i][j] < arr[i][j-1]) { left = process(arr, i, j - 1, cache); } if (j + 1 < arr[0].length && arr[i][j] < arr[i][j+1]) { right = process(arr, i, j + 1, cache); } cache[i][j] = Math.max(Math.max(up, down), Math.max(left, right)) + 1; return cache[i][j]; }
|
给定两个非负数组x和hp,长度都是N,再给定一个正数range,x有序,x[i]表示i号怪兽在x轴上的位置,hp[i]表示i号怪兽的血量,再给定一个正数range,表示如果法师释放技能的范围长度,被打到的每只怪兽损失1点血量。返回要把所有怪兽血量清空,至少需要释放多少次AOE技能?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public int AOEGreedy(int[] x, int[] hp, int range) { int ans = 0; int n = x.length; int[] cover = new int[n]; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { if (x[j] - x[i] <= range) { cover[i] = j; } } } for (int i = 0; i < n; i++) { if (hp[i] <= 0) { continue; } int hitTime = hp[i]; for (int j = i; j <= cover[i]; j++) { hp[j] -= hitTime; } ans += hitTime; } return ans; }
|
给定一个数组arr,你可以在每个数字之前决定+或者-但是必须所有数字都参与,再给定一个数target,请问最后算出target的方法数
https://leetcode-cn.com/problems/target-sum/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Solution { public int findTargetSumWays(int[] nums, int target) { Map<Integer, Map<Integer, Integer>> cache = new HashMap<>(); return process(nums, 0, target, cache); } public int process(int[] arr, int index, int rest, Map<Integer, Map<Integer, Integer>> cache) { if (cache.containsKey(index) && cache.get(index).containsKey(rest)) { return cache.get(index).get(rest); } if (index == arr.length) { return rest == 0 ? 1 : 0; } int ans = process(arr, index + 1, rest - arr[index], cache) + process(arr, index + 1, rest + arr[index], cache); if (!cache.containsKey(index)) { cache.put(index, new HashMap<>()); } cache.get(index).put(rest, ans); return ans; } }
|
优化:转化为01背包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class Solution { public int findTargetNum(int[] arr, int target) { int sum = 0; for (int i = 0; i < arr.length; i++) { if (arr[i] < 0) { arr[i] = -arr[i]; } sum += arr[i]; } return sum < target || ((target & 1) ^ (sum & 1)) != 0 ? 0 : subset(arr, (target + sum) >> 1); }
public int subset(int[] arr, int s) { if (s < 0) { return 0; } int n = arr.length; int[][] dp = new int[n + 1][s + 1]; dp[0][0] = 1; for (int i = 1; i <= n; i++) { for (int j = 0; j <= s; j++) { dp[i][j] = dp[i - 1][j]; if (j - arr[i - 1] >= 0) { dp[i][j] += dp[i - 1][j - arr[i - 1]]; } } } return dp[n][s]; } }
|
优化:动态规划的空间压缩(递推公式只与上一行有关,可用一维数组代替二维数组)
1 2 3 4 5 6 7 8 9 10 11 12 13
| public int subset(int[] arr, int s) { if (s < 0) { return 0; } int[] dp = new int[s + 1]; dp[0] = 1; for (int n : arr) { for (int i = s; i >= n; i--) { dp[i] += dp[i - n]; } } return dp[s]; }
|
返回一个数组中子数组最大累加和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public int maxSubArraySum(int[] arr) { int[] dp = new int[arr.length]; dp[0] = arr[0]; int maxSum = dp[0]; for (int i = 1; i < arr.length; i++) { dp[i] = Math.max(dp[i-1] + arr[i], arr[i]); maxSum = Math.max(maxSum, dp[i]); } return maxSum; }
public int maxSubArraySum2(int[] arr) { int dp = arr[0]; int maxSum = dp; for (int i = 1; i < arr.length; i++) { dp = Math.max(dp + arr[i], arr[i]); maxSum = Math.max(maxSum, dp); } return maxSum; }
|
返回一个数组中所选数字不能相邻的情况下最大子序列累加和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class solution { public int subArrMaxSumNotAdjacent(int[] arr) { if (arr == null || arr.length == 0) { return 0; } if (arr.length == 1) { return arr[0]; } if (arr.length == 2) { return Math.max(arr[0], arr[1]); } int[] dp = new int[arr.length]; dp[0] = arr[0]; dp[1] = arr[1]; for (int i = 2; i < arr.length; i++) { dp[i] = Math.max(Math.max(dp[i-2] + arr[i], arr[i]), dp[i-1]); } return dp[arr.length - 1]; } }
|
给你一个整数数组 nums 和一个目标值 goal 。你需要从 nums
中选出一个子序列,使子序列元素总和最接近 goal
。也就是说,如果子序列元素和为 sum ,你需要 最小化绝对差 abs(sum - goal)
。返回 abs(sum - goal) 可能的 最小值
。注意,数组的子序列是通过移除原始数组中的某些元素(可能全部或无)而形成的数组。
链接:https://leetcode-cn.com/problems/closest-subsequence-sum
分治思路:将n个数字分为2份,每份分别计算所有可能的组合情况的序列和,求第一份中最接近的,第二份中最接近的,两份中取两个相加最接近的(先取左侧一个数字a,计算goal-a,在右侧二分查找),再比较三者哪个最接近
Think:分3,4,5...份行不行
给定一个有序数组arr,其中值可能为正、负、0。返回arr中每个数都平方之后不同的结果有多少种?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public class Solution {
public int power2Diff1(int[] arr) { if (arr == null || arr.length == 0) { return 0; } Set<Integer> powers = new HashSet<>(); for (int i = 0; i < arr.length; i++) { powers.add(Math.abs(arr[i])); } return powers.size(); }
public int power2Diff2(int[] arr) { if (arr == null || arr.length == 0) { return 0; } int L = 0; int R = arr.length - 1; int ans = 0; int LAbs = 0; int RAbs = 0; while (L <= R) { LAbs = Math.abs(arr[L]); RAbs = Math.abs(arr[R]); if (LAbs < RAbs) { while (R >= 0 && Math.abs(arr[R]) == RAbs) { R--; } } else if (LAbs > RAbs) { while (L < arr.length && Math.abs(arr[L]) == LAbs) { L++; } } else { while (L < arr.length && Math.abs(arr[L]) == LAbs) { L++; } while (R >= 0 && Math.abs(arr[R]) == RAbs) { R--; } } ans++; } return ans; } }
|
给定一个数组arr,先递减然后递增,返回arr中有多少个不同的数字?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class Solution { public int diffNum(int[] arr) { if (arr == null || arr.length == 0) { return 0; } int N = arr.length; int L = 0; int R = N-1; int diffNum = 0; while (L <= R) { int lvalue = arr[L]; int rvalue = arr[R]; if (lvalue < rvalue) { while (R >= 0 && arr[R] == rvalue) { R--; } } else if (lvalue > rvalue) { while (L < N && arr[L] == lvalue) { L++; } } else { while (L < N && arr[L] == lvalue) { L++; } while (R >= 0 && arr[R] == rvalue) { R--; } } diffNum++; } return diffNum; } }
|