1、数组
代码随想录
LeetCode 题解
数组问题最常见
滑动窗口:窗口大小固定还是不固定,什么时候应该扩展窗口
1、二分查找
public int search(int[] nums, int target) {
int l = 0;
int r = nums.length - 1;
int mid;
while (l <= r) {
mid = l + (r - l) / 2;
if (nums[mid] == target) return mid;
if (nums[mid] > target) r = mid - 1;
else l = mid + 1;
}
return -1;
}
2、移除元素
public int removeElement(int[] nums, int val) {
// [end ... nums.length - 1] = val
int end = nums.length;
int i = 0;
while (i < end) {
if (nums[i] == val) swap(nums, i, --end);
else i++;
}
return end;
}
private void swap(int[] nums, int a, int b) {
int k = nums[a];
nums[a] = nums[b];
nums[b] = k;
}
3、有序数组的平方
public int[] sortedSquares(int[] nums) {
int[] arr = new int[nums.length];
int i = arr.length - 1;
// 合并两个降序数组, 得到一个升序数组
int p1 = 0;
int p2 = nums.length - 1;
while (p1 <= p2) {
if (Math.abs(nums[p1]) > Math.abs(nums[p2])) {
arr[i--] = nums[p1] * nums[p1];
p1++;
} else {
arr[i--] = nums[p2] * nums[p2];
p2--;
}
}
return arr;
}
4、长度最小的子数组
窗口大小不固定,和小于目标的时候应该扩展窗口
public int minSubArrayLen(int target, int[] nums) {
int l = 0, r = -1; // [l ... r] 是滑动窗口
int sum = 0; // sum = 滑动窗口的和
int res = nums.length + 1;
// 窗口的左边界在数组范围内, 则循环继续
while (l < nums.length) {
if (r + 1 < nums.length && sum < target) sum += nums[++r];
else sum -= nums[l++];
if (sum >= target) res = Math.min(res, r - l + 1);
}
return res != nums.length + 1 ? res : 0;
}
5、螺旋矩阵 II
// l r
// 1 2 3 t
// 8 9 4
// 7 6 5 b
public int[][] generateMatrix(int n) {
int[][] arr = new int[n][n];
int num = 1;
int left = 0, right = n - 1;
int top = 0, bottom = n - 1;
while (num <= n * n) {
for (int i = left; i <= right; i++) arr[top][i] = num++; // 向右填充
top++;
for (int i = top; i <= bottom; i++) arr[i][right] = num++; // 向下填充
right--;
for (int i = right; i >= left; i--) arr[bottom][i] = num++; // 向左填充
bottom--;
for (int i = bottom; i >= top; i--) arr[i][left] = num++; // 向上填充
left++;
}
return arr;
}
6、更多题目
窗口大小不固定,当前无重复字符的时候应该扩展窗口
public int lengthOfLongestSubstring(String s) {
int l = 0, r = -1; // [0 ... r] 是滑动窗口
int[] freq = new int[256]; // freq[c] = 滑动窗口中字符 c 的频率
int res = 0;
// 窗口的左边界在字符串范围内, 则循环继续
while (l < s.length()) {
if (r + 1 < s.length() && freq[s.charAt(r + 1)] == 0) freq[s.charAt(++r)]++;
else freq[s.charAt(l++)]--;
res = Math.max(res, r - l + 1);
}
return res;
}
窗口大小固定
public List<Integer> findAnagrams(String s, String p) {
List<Integer> res = new LinkedList<>();
if (s.length() < p.length()) return res;
int[] freq_p = new int[26]; // freq_p 目标频率
for (char c : p.toCharArray()) freq_p[c - 'a']++;
int l = 0, r = p.length() - 1; // [l ... r] 是滑动窗口
int[] freq_s = new int[26]; // freq_s[c] = 滑动窗口中字符 c 的频率
for (int i = 0; i < p.length(); i++) freq_s[s.charAt(i) - 'a']++;
if (same(freq_p, freq_s)) res.add(0);
while (true) {
if (r == s.length() - 1) break;
r++;
freq_s[s.charAt(r) - 'a']++;
freq_s[s.charAt(l) - 'a']--;
l++;
if (same(freq_p, freq_s)) res.add(l);
}
return res;
}
private boolean same(int[] freq_p, int[] freq_s) {
for (int i = 0; i < 26; i++) {
if (freq_p[i] != freq_s[i]) return false;
}
return true;
}
窗口大小不固定,还没覆盖完目标的时候应该扩展窗口
public String minWindow(String s, String t) {
if (s.length() < t.length()) return "";
// 目标
int[] freq_t = new int[256];
for (char c : t.toCharArray()) freq_t[c]++;
// 窗口 [l ... r]
int l = 0, r = -1;
int[] freq_s = new int[256];
int count = 0; // 窗口中包含 t 中字符的数量
int startIndex = -1;
int minLength = s.length() + 1;
while (l < s.length()) {
if (r + 1 < s.length() && count < t.length()) {
r++;
char c = s.charAt(r);
freq_s[c]++;
if (freq_s[c] <= freq_t[c]) count++;
} else {
char c = s.charAt(l);
l++;
freq_s[c]--;
if (freq_s[c] < freq_t[c]) count--;
}
if (count == t.length() && r - l + 1 < minLength) {
startIndex = l;
minLength = r - l + 1;
}
}
if (startIndex == -1) return "";
return s.substring(startIndex, startIndex + minLength);
}
本文来自博客园,作者:lidongdongdong~,转载请注明原文链接:https://www.cnblogs.com/lidong422339/p/17440641.html