下面给出10道高频数组经典算法题,覆盖双指针、滑动窗口、前缀和、排序、原地操作、二分查找等主流解法,每题附带题意、思路、完整Java代码,适合刷题复盘。
例题1:移除元素(同向快慢指针)
题目
原地删除数组中值等于val的元素,返回新数组长度,不能使用额外数组。
public int removeElement(int\[\] nums, int val) {
int slow = 0;
for (int fast = 0; fast < nums.length; fast++) {
if (numsfast != val) {
numsslow++ = numsfast;
}
}
return slow;
}
例题2:有序数组去重
题目
升序排列数组,原地删除重复元素,每个元素只保留一次,返回新长度。
public int removeDuplicates(int\[\] nums) {
if (nums.length == 0) return 0;
int slow = 0;
for (int fast = 1; fast < nums.length; fast++) {
if (numsfast != numsslow) {
nums++slow = numsfast;
}
}
return slow + 1;
}
例题3:移动零
题目
把数组中所有0移动到末尾,非零元素相对顺序不变,原地操作。
public void moveZeroes(int\[\] nums) {
int idx = 0;
for (int i = 0; i < nums.length; i++) {
if (numsi != 0) {
int tmp = numsidx;
numsidx = numsi;
numsi = tmp;
idx++;
}
}
}
例题4:两数之和(有序数组,对撞双指针)
题目
升序数组numbers,找出两个下标(从1开始)使得两数相加等于target,唯一解。
public int\[\] twoSum(int\[\] numbers, int target) {
int left = 0, right = numbers.length - 1;
while (left < right) {
int sum = numbersleft + numbersright;
if (sum == target) {
return new int\[\]{left + 1, right + 1};
} else if (sum < target) {
left++;
} else {
right--;
}
}
return new int\[\]{};
}
例题5:长度最小的子数组(滑动窗口)
题目
正整数数组,找出连续子数组和 ≥ target 的最小长度,不存在返回0。
public int minSubArrayLen(int target, int\[\] nums) {
int left = 0, sum = 0;
int minLen = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
sum += numsright;
while (sum >= target) {
minLen = Math.min(minLen, right - left + 1);
sum -= numsleft++;
}
}
return minLen == Integer.MAX_VALUE ? 0 : minLen;
}
例题6:三数之和(排序+双指针)
题目
数组中找出所有不重复三元组满足 a+b+c=0。
import java.util.*;
public List<List> threeSum(int\[\] nums) {
List<List> res = new ArrayList<>();
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
if (numsi > 0) break;
if (i > 0 && numsi == numsi - 1) continue;
int l = i + 1, r = nums.length - 1;
while (l < r) {
int sum = numsi + numsl + numsr;
if (sum == 0) {
res.add(Arrays.asList(numsi, numsl, numsr));
while (l < r && numsl == numsl + 1) l++;
while (l < r && numsr == numsr - 1) r--;
l++;
r--;
} else if (sum < 0) {
l++;
} else {
r--;
}
}
}
return res;
}
例题7:旋转数组(数组轮转)
题目
将数组向右轮转k个位置。
public void rotate(int\[\] nums, int k) {
k %= nums.length;
reverse(nums, 0, nums.length - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, nums.length - 1);
}
private void reverse(int\[\] nums, int l, int r) {
while (l < r) {
int t = numsl;
numsl = numsr;
numsr = t;
l++;
r--;
}
}
例题8:搜索插入位置(二分查找)
题目
升序数组,查找target,存在返回下标;不存在返回插入位置。
public int searchInsert(int\[\] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (numsmid == target) return mid;
else if (numsmid < target) left = mid + 1;
else right = mid - 1;
}
return left;
}
例题9:最大子数组和(动态规划)
题目
求连续子数组的最大累加和。
public int maxSubArray(int\[\] nums) {
int pre = 0, maxAns = nums0;
for (int x : nums) {
pre = Math.max(pre + x, x);
maxAns = Math.max(maxAns, pre);
}
return maxAns;
}
例题10:滑动窗口最大值(单调队列)
题目
给定数组和窗口k,输出每个窗口内最大值。
import java.util.*;
public int\[\] maxSlidingWindow(int\[\] nums, int k) {
Deque deque = new ArrayDeque<>();
int\[\] res = new intnums.length - k + 1;
int idx = 0;
for (int right = 0; right < nums.length; right++) {
while (!deque.isEmpty() && numsright >= numsdeque.peekLast()) {
deque.pollLast();
}
deque.offerLast(right);
// 移除窗口外下标
while (deque.peekFirst() <= right - k) {
deque.pollFirst();
}
if (right >= k - 1) {
residx++ = numsdeque.peekFirst();
}
}
return res;
}
题型归类
-
快慢指针原地修改:例题1、2、3
-
对撞双指针:例题4、6
-
滑动窗口:例题5、10
-
数组翻转/旋转:例题7
-
二分查找:例题8
-
DP子数组最值:例题9