代码随想录——数组篇

(一)二分查找法

关键:边界的确定

[left,right]

[left,right)

在循环中必须始终坚持一种区间定义

while(left<right)/(left≤right)

if(nums[middle] > target) right=middle/middle-1

(一)左闭右闭区间 [left, right]

left=0;
//区间包含right,对于数组,下标从0-numsize-1
right = numsize -1;
//对于左闭右闭区间,[1,1]区间是合法的,因此必须包含在内,带等号
while(left <= right){
  middle = (left+right)/2;
  if(nums[middle]>target)
    right = middle -1;
  //因为已经判断了middle位置的值不合法,因此对于左闭右闭区间,必须把这个middle剔除
  else if(nums[middle] < target)
    left = middle + 1; //同理如上
  else
    return middle;
} 
return -1;//一直没有找到
  

(二)左闭右开区间 [left, right)

left=0;
//因为该区间不包含right,所以right=numsize
right = numsize;
//对于左闭右开区间,[1,1)区间是不合法的,因此不能带等号
while(left < right){
  middle = (left+right)/2;
  if(nums[middle]>target)
    //对于左闭右开区间,本身就不包含middle,因此不需要-1
    right = middle;
  else if(nums[middle] < target)
    // 对于左闭右开区间,左边是包含的,所以要剔除middle
    left = middle + 1; 
  else
    return middle;
} 
return -1;//一直没有找到
  

总结:根据不同的区间定义,left和right的边界取值需要注意。

(二)移除元素

数组中的元素不可以被删除,只能被覆盖

vector 中的erase函数

erase为一个O(N)的函数,删掉一个元素,后面所有元素前移

法一:暴力实现(双for循环 O(N*N))

法二:双指针(O(N))

一层for循环

快指针(fast):寻找旧数组中需要删除的元素,将需要保留的元素赋值给新数组

慢指针(slow):新数组的当前下标(在旧数组基础上更新)

slow = 0;
//移动快指针
for(fast = 0;fast < nums.size; fast++)
  if(nums[fast] != val){  //需要保留的元素,更新新数组
    nums[slow] = nums[fast];  (nums[slow++]=nums[fast])
    slow++; //慢指针后移
  }
return slow; 

(三)有序数组的平方

平方后的大小

大 → 小 ← 大

(左指针)(右指针)

双指针方法,由两边向中间推进,新的数组由大向小填入

vector<int> result;
k = nums.size - 1; // 新数组由大到小填入
for(i = 0, j = nums.size - 1; i < = j;)
  if(nums[i]^2 > nums[j]^2){  //取左边元素
    result[k] = nums[i]^2;
    k--;
    i++;
  }else{ //包括小于和等于
    result[k] = nums[j]^2;
    k--;
    j--;
  }
return result;
class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        vector<int> result(nums.size(),0);
        int k = nums.size() - 1;
        for(int i=0,j=nums.size()-1; i <= j;){
            if(nums[i]*nums[i] > nums[j]*nums[j]){
                result[k] = nums[i]*nums[i];
                i++;
                k--;
            }else{
                result[k] = nums[j]*nums[j];
                k--;
                j--;
            }
        }
        return result;
    }
};

(四)长度最小的子数组

滑动窗口(双指针法)

用for循环中的j确定终止位置

起始位置的确定(精华):

当发现起始和终止元素中的元素和大于s的时候,移动起始位置,缩小区间

result = Max;
// 用j指向终止位置,试探上界
for(j=0; j<= nums.size-1;j++){
  sum += nums[j];
  //这里不能是if(sum >= s),因为这里需要不断移动前指针,试探出符合sum>s的最短组合长度
  while(sum >= s){
    subL = j - i + 1;
    result = min(result,subL); //保留最小值
    sum - = nums[i]; // 前指针后移,sum要减去前指针当前元素值
    i++; //前指针后移
  } //end-while
} //end-for
return result;
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int result = INT32_MAX;
        int sum = 0;
        int subL = 0;
        int i = 0;
        for(int j = 0; j < nums.size(); j++){
            sum += nums[j];
            while(sum >= target){
                subL = j -i +1;
                result = result < subL ? result: subL;
                sum -= nums[i];
                i++;
            }
        }
        return result == INT32_MAX ? 0 : result;

    }
};

(五)螺旋矩阵

关键点:边界处理

循环不变量:对每条边的处理规则不变 (左闭右开 [ )/ 左闭右闭 [ ])

左闭右开法:

startx = 0; //起始位置行号
starty = 0; //起始位置列号
offset = 1; //终止位置的偏移量
count = 1; //矩阵赋值,从1到N*N

//循环遍数(转几圈)
while(n/2){
  //遍历上边, i不变
  for(j = starty; j < n - offset; j++){
    nums[startx][j] = count ++; 
  }
  //遍历右边,此时j=n-offset,j的值固定
  for(i = startx; i< n - offset; i++){
    nums[i][j] = count ++;
  }
  //遍历下边,此时j=n-offset,j不需要再初始化
  for(;j > starty; j--){
    nums[i][j] = count ++;
  }
  //遍历左边,此时i = n-offset, i不需要再初始化
  for(; i > startx; i--){
    nums[i][j] = count ++;
  }
  //每转一圈,更新startx,starty,offset
  startx ++;
  starty ++;
  offset ++;    
 }
 // 如果n为奇数,最后还需要填补最中间的空缺
 if(n%2 == 1) nums[i][j] = count;
class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> result(n, vector<int>(n,0));
        int startx = 0;
        int starty = 0;
        int offset = 1;
        int count = 1;
        int num = n/2;
        int mid = n/2;
        int i, j;
        while(num--){
            for(j = starty; j < n - offset; j++){
                result[startx][j] = count++;
            }
            for(i = startx; i < n - offset; i++){
                result[i][j] = count++;
            }
            for(; j > starty; j--){
                result[i][j] = count++;
            }
            for(; i> startx; i--){
                result[i][j] = count++;
            }
            startx++;
            starty++;
            offset++;
        }
        if(n%2 == 1) result[mid][mid] = count;
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值