方法一:遍历
1 2 3 4 5 6 7
| class Solution { public int numberOfEmployeesWhoMetTarget(int[] hours, int target) { int ans = 0; for (int x : hours) if (x >= target) ans++; return ans; } }
|
复杂度分析
- 时间复杂度:\(O(n)\)。
- 空间复杂度:\(O(1)\)。
方法一:暴力优化
比赛时本来是想滑窗的,但是当时没想通。而枚举左右端点再遍历的暴力方法,时间复杂度为 \(O(n^{3})\) 会超时。结果想半天发现可以使用前缀和的思路,先枚举左端点,然后一边遍历一边枚举右端点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public int countCompleteSubarrays(int[] nums) { int n = nums.length; Set<Integer> set = new HashSet<>(); for (int x : nums) set.add(x); int cnt = set.size(), ans = 0; for (int i = 0; i <= n - cnt; i++) { set.clear(); for (int j = i; j < n; j++) { set.add(nums[j]); if (set.size() == cnt) { ans += n - j; break; } } } return ans; } }
|
复杂度分析
- 时间复杂度:\(O(n^{2})\)。
- 空间复杂度:\(O(n)\)。
方法二:滑动窗口
枚举右端点,并且让窗口是完全子数组的前提下,使左端点尽可能靠右,此时所有小于等于左端点的位置,都满足条件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public int countCompleteSubarrays(int[] nums) { int n = nums.length; Set<Integer> set = new HashSet<>(); for (int x : nums) set.add(x); int cnt = set.size(); int lo = 0, hi = 0, ans = 0; Map<Integer, Integer> map = new HashMap<>(); while (hi < n) { map.merge(nums[hi++], 1, Integer::sum); if (map.size() == cnt) { while (map.get(nums[lo]) > 1) { map.merge(nums[lo++], -1, Integer::sum); } ans += lo + 1; } } return ans; } }
|
复杂度分析
- 时间复杂度:\(O(n)\)。
- 空间复杂度:\(O(n)\)。
方法一:枚举
枚举字符串 \(a,b,c\) 的全排列,然后从前往后合并,以消除公共字符。需要注意,如果字符串存在包含关系,则不需要进行合并操作。
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
| class Solution { public String minimumString(String a, String b, String c) { List<String> list = new ArrayList<>(); list.add(merge(merge(a, b), c)); list.add(merge(merge(a, c), b)); list.add(merge(merge(b, a), c)); list.add(merge(merge(b, c), a)); list.add(merge(merge(c, a), b)); list.add(merge(merge(c, b), a)); list.sort((s1, s2) -> { int m = s1.length(), n = s2.length(); if (m != n) return m - n; return s1.compareTo(s2); }); return list.get(0); }
private String merge(String a, String b) { if (a.contains(b)) return a; int m = a.length(), n = b.length(); for (int i = Math.min(m, n); ; i--) { if (a.substring(m - i).equals(b.substring(0, i))) { return a + b.substring(i); } } } }
|
复杂度分析
- 时间复杂度:\(O(n^{2})\),其中 \(n\) 为字符串 \(a,b,c\) 长度的最大值。
- 空间复杂度:\(O(n)\)。
方法一:数位DP
感觉有点像 DFS,枚举当前位的数字,多传递一个参数 isLimit
可以省去很多判断。
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
| class Solution { private static final int MOD = (int) 1e9 + 7;
public int countSteppingNumbers(String low, String high) { int m = low.length(), n = high.length(); int[][] dp = new int[n][10]; Arrays.fill(dp[0], 1); for (int i = 1; i < n; i++) { for (int j = 0; j < 10; j++) { if (j - 1 >= 0) dp[i][j] = (dp[i][j] + dp[i - 1][j - 1]) % MOD; if (j + 1 <= 9) dp[i][j] = (dp[i][j] + dp[i - 1][j + 1]) % MOD; } } return (f(dp, high, 0, -1, true) - f(dp, low, 0, -1, true) + valid(low) + MOD) % MOD; }
private int f(int[][] dp, String s, int i, int pre, boolean isLimit) { int n = s.length(); if (i == n) return pre != -1 ? 1 : 0; if (pre != -1 && !isLimit) return dp[n - i][pre]; int cur = s.charAt(i) - '0', res = 0; int hi = isLimit ? cur : 9; for (int j = 0; j <= hi; j++) { if (pre == -1 || Math.abs(j - pre) == 1) { res = (res + f(dp, s, i + 1, (pre == -1 && j == 0) ? -1 : j, isLimit && j == hi)) % MOD; } } return res; }
private int valid(String s) { int n = s.length(); for (int i = 1; i < n; i++) { if (Math.abs(s.charAt(i) - s.charAt(i - 1)) != 1) { return 0; } } return 1; } }
|
复杂度分析
- 时间复杂度:\(O(nm^{2})\),其中 \(n\) 为
high
的长度,\(m = 10\)。
- 空间复杂度:\(O(nm)\)。