方法一:遍历
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)\)。