【力扣】数组专题
在跟随代码随想录刷题的过程中,完成数组部分的相关题目,所以在此进行一个小总结。
本篇笔记涉及的力扣题目如下:【可以使用Ctrl+F进行搜索~】
数组相关问题的一点小总结
- 使用二分法对有序的数组进行元素查找,能够提高查找效率
- 对于数组问题,可采用快慢指针进行相关操作
题目:704. 二分查找
解题思路
- 思路:给定一个nums数组,注意数组是升序排列的;那么,找到当前target元素是否存在于数组之中,可采用二分法查找
- 使用left指向数组头,right指针指向数组尾,mid用于计算二分查找的位置,mid=left+(right-left)/2,避免由于left和right过大导致计算结果溢出的现象
- 如果当前nums[mid]比target大,那么就往左边找;反之,则向右边找;如果相等,说明找到了,返回当前的mid值即可
- 结束条件,当前的left移动到了right的右边,则说明两指针之间已不存在元素,则返回-1即可
Java代码实现
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left <= right) {
int mid = left + (right-left)/2;
if(nums[mid] > target) {
right = mid - 1;
} else if(nums[mid] < target) {
left = mid + 1;
} else {
return mid;
}
}
return -1;
}
}
参考资料:704. 二分查找
题目:27. 移除元素
解题思路
- 给定一个数组,以及一个需要删除的值;要求在O(1)的空间复杂度中完成
- 可考虑采用快慢指针的方式,left用于记录当前需要进行替换的元素,right指针用于遍历整个数组
- 当right指针所指的值 是 删除元素 时,那么right右移,left不动即可
- 若不是,那么将right所指值赋值给left即可
- 当left和right指向同一位置是否有影响?当前right所指值不需要删除,所以将right所指位置的值赋值给left,即将当前位置的元素赋值给当前元素,自己替换自己,不影响结果。
Java代码实现
class Solution {
public int removeElement(int[] nums, int val) {
if(nums == null || nums.length == 0){
return 0;
}
int left = 0;
for(int right=0; right<nums.length; right++) {
if(nums[right] != val) {
nums[left] = nums[right];
left++;
}
}
return left;
}
}
参考资料:27. 移除元素
题目:977. 有序数组的平方
解题思路
- 给定一个非递减序列的数组,要求返回每个数字的平方,且按照非递减序列排序;观察数组可知,一个数进行平方之后,最大值只能出现在数组头或数组尾,因而比较两位置的平方后填入res数组中即可
- 设置双指针,left指向头,right指向尾;将结果按照从大到小的顺序倒序放在res中即可
- 如果将left所指值的平方,放在res中,那么将left右移;否则,将right左移
- 需要注意的是,如果使用Math.pow函数,其返回值是double类型,需要将其类型转化为int类型
Java代码实现
class Solution {
public int[] sortedSquares(int[] nums) {
int len = nums.length;
int[] res = new int[len];
int left = 0;
int right = len-1;
for(int i=len-1; i>=0; i--) {
// if(nums[left] * nums[left] > nums[right] * nums[right]) {
// res[i] = nums[left] * nums[left];
// left++;
// } else {
// res[i] = nums[right] * nums[right];
// right--;
// }
res[i] = Math.abs(nums[left]) > Math.abs(nums[right]) ? (int) Math.pow(Math.abs(nums[left++]), 2) : (int) Math.pow(Math.abs(nums[right--]), 2);
}
return res;
}
}
参考资料
题目:209. 长度最小的子数组
解题思路:
- 初始化最小长度,设置为最大值,当最小长度变小时,该值更新
- 设置left和right指针,left指针用于记录左边界,当求和sum大于target时,左指针右移;right指针记录右边界,当求和sum小于target时,右指针右移,继续寻找符合要求的子字符串。
- 当右边界符合题目要求时,更新最小长度minLength
Java代码实现
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int res = Integer.MAX_VALUE;
int left = 0;
int right = 0;
int temp = 0;
while(right < nums.length){
temp += nums[right];
while(temp >= target) {
res = Math.min(res, right - left + 1);
temp -= nums[left];
left++;
}
right++;
}
return res==Integer.MAX_VALUE ? 0 : res;
}
}
参考资料:209.长度最小的子数组
题目:59. 螺旋矩阵 II
解题思路
- 手动模拟螺旋矩阵,分别实现四个方向的代码,将数组依次填入数组中即可
- 需要注意的是,如果n为奇数,说明最后只剩下中间的一个位置,将最后一个数直接填入即可;若n为偶数,则正好能够遍历n/2遍
Java代码实现
class Solution {
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
int count = 1;
int start = 0;
int loop = 0;
int i, j;
while(loop++ < n/2) {
for(j=start; j<n-loop; j++) {
res[start][j] = count++;
}
for(i=start; i<n-loop; i++) {
res[i][j] = count++;
}
for(; j>=loop; j--) {
res[i][j] = count++;
}
for(; i>=loop; i--) {
res[i][j] = count++;
}
start++;
}
if(n % 2 == 1) {
res[start][start] = count;
}
return res;
}
}
参考资料:59. 螺旋矩阵 II
题目: 15. 三数之和
解题方法
- 思路:将数组按照从小到大的顺序排列,使用双指针法;依次判断三数之和是否等于0,若不等于,则尝试通过移动指针使其符合要求。需要注意:去重操作
- 定义一个ArrayList用于存放结果
- 将数组从小到大排序,此时遍历一遍数组即可
- 分别定义i, left, right三个指针,分别指向当前元素,当前元素的下一个,以及最后一个元素
- 使用sum记录三数之和,若sum>0表示三数之和较大,故需要减小最大值,即将right--;同理,sum<0,left++
Java代码实现
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
// 创建一个result数组,用于记录结果
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
for(int i=0; i<nums.length; i++){
// 排序后数组的第一个元素大于0,则不存在相加为0的三元组
if(nums[i] > 0){
return result;
}
/*
去重操作:若nums[i-1]==nums[i]
表示nums[i-1]与其他的元素构成的三元组与nums[i]构成的相同【存在重复三元组】
e.g. 示例一:nums = [-1,0,1,2,-1,-4]
排好序后nums = [-4,-1,-1,0,1,2]
-1 + 0 + 1 = 0
-1+ 0 + 1 = 0
*/
if(i>0 && nums[i-1]==nums[i]){
continue;
}
int left=i+1, right=nums.length-1;
int sum,temp; //sum记录总和,判断是否等于0;temp记录i+right值
while(left < right){
sum = nums[i] + nums[left] + nums[right];
// sum>0表示三数之和较大,故需要减小最大值,即将right--;同理,sum<0,left++
if(sum > 0){
right--;
} else if(sum < 0){
left++;
} else {
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
// 对b和c去重,若right和right-1所指的值相同,则将right--,即跳过right-1
while(right>left &&nums[right] == nums[right-1]){
right--;
}
while(right>left &&nums[left] == nums[left+1]){
left++;
}
right--;
left++;
}
}
}
return result;
}
}
参考资料:
题目:18. 四数之和
解题思路
- 思路和上述15. 三数之和相同
- 使用四个指针,i, j, left, right;i从0开始,j=i+1,left=j+1,right=nums.length-1
- 首先确定i和j,移动left和right,确定四元组;left从前向后移动,right从后向前移动
- 遍历完成数组一遍后,将i, j后移,重复上述过程
- 题目要求,需要取出重复的四元组,所以在i,j开始遍历前,判断当前的i, j是否和前一个元素相同,进行去重【continue】;在找到一个四元组后,对left和right所指元素进行去重操作【移动指针】
Java代码实现
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
for(int i=0; i<nums.length; i++){
if(nums[i]>0 && nums[i]>target){
return result;
}
// 对i去重
if(i>0 && nums[i-1] == nums[i]){
continue;
}
for(int j=i+1; j<nums.length; j++){
// 对j去重
if(j>i+1 && nums[j-1] == nums[j]){
continue;
}
int left=j+1, right=nums.length-1;
while(left<right){
long sum;
sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
if(sum > target){
right--;
} else if(sum<target){
left++;
} else {
result.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
// 对left和right进行去重
while(left<right && nums[right-1] == nums[right]) right--;
while(left<right && nums[left+1] == nums[left]) left++;
right--;
left++;
}
}
}
}
return result;
}
}

浙公网安备 33010602011771号