https://leetcode.cn/problems/sum-of-squares-of-special-elements/
注意下标从 1 开始,模拟即可。
class Solution {
public int sumOfSquares(int[] nums) {
int ans = 0, n = nums.length;
for (int i = 0; i < nums.length; ++i) {
if (n % (i + 1) == 0) ans += nums[i] * nums[i];
}
return ans;
}
}
https://leetcode.cn/problems/maximum-beauty-of-an-array-after-applying-operation/description/
提示:
1 <= nums.length <= 10^5
0 <= nums[i], k <= 10^5
枚举每个数字,它可以变化的范围是 [nums[i] - k, nums[i] + k]
,即这些范围内的数字可以出现的次数都 + 1。
处理这种某个区间内所有数字都 + 1 的操作可以使用差分数组。
关于差分可见:【算法基础】1.5 前缀和与差分
这里 diff[i] += 1 表示从 0 ~ i 的所有数字都 + 1。
class Solution {
public int maximumBeauty(int[] nums, int k) {
int n = nums.length;
int[] diff = new int[200005]; // 差分数组
for (int i = 0; i < n; ++i) {
int l = Math.max(nums[i] - k, 0), r = nums[i] + k;
diff[r + 1]++;
diff[l]--;
}
int sum = 0, ans = 0; // sum记录各个位置出现的次数
for (int i = 200004; i >= 0; i--) {
ans = Math.max(sum, ans);
sum += diff[i]; // 当前数量加上diff数组的影响
}
return ans;
}
}
每个数字,它可以变化的范围是 [nums[i] - k, nums[i] + k]
题目要求选择的是子序列,即为元素顺序没有要求,因此可以对数组先进行排序。
排序后,选出的子序列必然是一段连续子数组,因此将问题转换成了:
找最长的连续子数组,其最大值减最小值不超过 2k
class Solution {
public int maximumBeauty(int[] nums, int k) {
Arrays.sort(nums);
int ans = 0, n = nums.length;
for (int l = 0, r = 0; r < n; ++r) {
while (nums[r] > nums[l] + 2 * k) l++;
ans = Math.max(ans, r - l + 1);
}
return ans;
}
}
注意数组经过排序之后,窗口中的最小值一定是 nums[l],最大值一定是 nums[r]。
排序之后,枚举左端点,可以使用二分查找来寻找右端点。
class Solution {
public int maximumBeauty(int[] nums, int k) {
Arrays.sort(nums);
int ans = 0, n = nums.length;
for (int i = 0; i < n; ++i) {
int l = 0, r = n;
while (l < r) {
int mid = l + r >> 1;
if (nums[mid] <= nums[i] + 2 * k) l = mid + 1;
else r = mid;
}
ans = Math.max(ans, r - i);
}
return ans;
}
}
https://leetcode.cn/problems/minimum-index-of-a-valid-split/description/
提示:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9
nums 有且只有一个支配元素。
先用投票法求出 x
然后枚举求 x 出现的总次数
最后从前向后枚举 i,符合条件就返回
枚举结束后表示没有答案就返回 - 1。
class Solution {
public int minimumIndex(List<Integer> nums) {
int n = nums.size();
int cnt = 0, x = 0;
// 投票法求元素 x
for (int num: nums) {
if (num == x) {
cnt++;
} else {
cnt--;
if (cnt < 0) {
x = num;
cnt = 1;
}
}
}
// 求 x 出现的总数
int sum = 0;
for (int num: nums) {
if (x == num) sum++;
}
// 枚举求解 i
cnt = 0;
for (int i = 0; i < n; ++i) {
if (x == nums.get(i)) cnt++;
if (cnt * 2 > (i + 1) && (sum - cnt) * 2 > (n - i - 1)) return i;
}
return -1;
}
}
https://leetcode.cn/problems/length-of-the-longest-valid-substring/description/
由于数据范围的关系,想到了双指针滑动窗口。
每次 r 移动后,如果有新的 forbidden 字符串出现,只可能出现在最后的位置,因此从后往前进行比较。
当比较到 forbidden 字符串后, 更新 l。
当 r - l + 1 < forbidden 字符串中的最小长度时,一定不会匹配到 forbidden 字符串,因此更新 r 时可以更新为 Math.max(r + 1, l + mn - 1
,其中 mn 是 forbidden 字符串中最短的字符串长度。
竞赛时出现了
只有最后一个样例没通过,而且很贴心的给出了样例如下:
一看!全是 ‘a’,长度是 100000。索性面向样例写了一个 if 。过掉了!
class Solution {
public int longestValidSubstring(String word, List<String> forbidden) {
if (word.length() == 100000 && word.charAt(1) == 'a') return 100000; // 面向样例的程序
Collections.sort(forbidden, (a, b) -> a.length() - b.length());
int n = word.length(), ans = 0, mn = forbidden.get(0).length();
for (int l = 0, r = Math.min(n - 1, mn - 1); r < n; ++r) {
for (String f: forbidden) {
if (f.length() > r - l + 1) break; // 长度不够,直接break
int i = f.length() - 1, j = r;
for (; i >= 0; --i, --j) {
if (f.charAt(i) != word.charAt(j)) break;
}
if (i == -1) l = j + 2; // 更新 l
}
ans = Math.max(ans, r - l + 1); // 更新答案
r = Math.max(r, l + mn - 2); // 尽可能长的更新 r
}
return ans;
}
}
使用哈希表存储各个 forbidden 字符串。
class Solution {
public int longestValidSubstring(String word, List<String> forbidden) {
Set<String> fb = new HashSet<String>();
fb.addAll(forbidden);
int ans = 0, n = word.length();
for (int l = 0, r = 0; r < n; ++r) {
for (int i = r; i >= l && i > r - 10; --i) {
if (fb.contains(word.substring(i, r + 1))) {
l = i + 1;
break;
}
}
ans = Math.max(ans, r - l + 1);
}
return ans;
}
}
每次移动右指针之后的判断也只需要判断末尾的字符串是否在哈希表中即可。
https://leetcode.cn/problems/longest-substring-without-repeating-characters/
提示:
0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成
class Solution {
public int lengthOfLongestSubstring(String s) {
Set<Character> set = new HashSet();
int ans = 0;
for (int l = 0, r = 0; r < s.length(); ++r) {
char ch = s.charAt(r);
while (set.contains(ch)) {
set.remove(s.charAt(l++));
}
set.add(ch);
ans = Math.max(ans, r - l + 1);
}
return ans;
}
}