【代码随想录】【LeetCode】学习笔记02-数组

vector容器

vector容器位于头文件vector中,这是一种类似链表的结构,可以实现动态增长和删除,简单用法如下。
要注意vector 和 array的区别,vector的底层实现是array,严格来讲vector是容器,不是数组。

几种vector声明:
vectorvec1; //定义空的vector
vectorvec2(10); //产生大小为10的vector
vectorvec3(10,-1); //产生大小为10,并且每个元素都是-1的vector
vectorvec4(v3); //用一个vector产生一个vector
尾部插入元素: vec.push_back(a);
尾部删除元素: vec.pop_back(a);
插入元素: vec.insert(vec.begin()+i,a);在第i+1个元素前面插入a;
删除元素: vec.erase(vec.begin()+2);删除第3个元素
vec.erase(vec.begin()+i,vec.end()+j);删除区间[i,j-1];区间从0开始
向量大小: vec.size();
清空: vec.clear();
实用迭代器访问元素:
vector::iterator ita; //声明一个迭代器
int i=0;
for(ita=v1.begin(), i=0;ita != v1.end();i++,ita++){}//v1.begin()指向v1的第一个元素,v1.end()指向最后元素的下一位置。

704. 二分查找

用的是[low , high]双闭区间法,依旧是笔记写在注释里了

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0, right = nums.size()-1;
        int mid = left + (right-left)/2;
        while(left<=right){//<=必须是小于等于,因为可能有只有1个数字(L==R)的情况
            if(nums[mid]>target){
                right = mid-1;///闭区间,不能重叠了,否则会超出时间限制
                mid = left + (right-left)/2;
            }
            else if(nums[mid]<target){
                left = mid+1;
                mid = left + (right-left)/2;
            }
            else if(nums[mid]==target) return mid;
        }
        return -1;
    }
};

27. 移除元素(双指针)

双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组和链表操作的面试题,都使用双指针法。
// 时间复杂度:O(n)
// 空间复杂度:O(1)

//slow 是用来标记【与val相等的位置】,fast用来标记【当前位置】(不停留,向前推进),相等
//【相等】就不更新,【不相等】就更新,与想当然的“相等就挪后面的值过来”相反
//更偏向数学问题 or 快慢指针固有?
//指针只是一种思路,用来“刻舟”的标记点而已,本题中双指针类型均为(int)。

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int x = 0, y = 0;
        while(y<nums.size()){
            if(nums[y]!=val){
                nums[x]=nums[y];
                x++;
            }
            y++;
        }
        return x;
    }
};

977.有序数组的平方(双指针)

数组其实是有序的, 只不过负数平方之后可能成为最大数了。
那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
此时可以考虑双指针法了,i指向起始位置,j指向终止位置。
定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。

注意此处for的写法(两个初始值;判断条件是二者作比较;最后没有+±-:for (int i = 0, j = A1.size() - 1; i <= j;)

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        if(nums[0]>=0) {
            for(int i = 0; i<nums.size(); i++) {  nums[i] = nums[i]*nums[i];  }
            return nums;
        }
        vector<int> result(nums.size(), 0);
        int l=0, r=nums.size()-1;
        int count = nums.size()-1;
        while(l<=r&&count>=0){
            if(-nums[l]>=nums[r]){
                result[count]=nums[l]*nums[l];
                count--;
                l++;
            }
            else{
                result[count] = nums[r]*nums[r];
                count--;
                r--;
            }
        }
        return result;
    }
};
//不要求原地改,则可以区分于上一题,做一个新数组
//“已排序”===》双指针

209. 长度最小的子数组(滑动窗口)

接下来就开始介绍数组操作中另一个重要的方法:滑动窗口
所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
那么滑动窗口如何用一个for循环来完成这个操作呢。
只用一个for循环,那么这个循环的索引,一定是表示 滑动窗口的终止位置

滑动窗口也可以理解为双指针法的一种!只不过这种解法更像是一个窗口的移动

不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int result = INT_MAX;
        int l=0;int r = 0;
        int sum = 0;
        while(r<nums.size()){
        //for(r = 0,l=0; r<nums.size();r++){【已知遍历终点的话,用for最好,不然r++必须放在最后,很有讲究】
            sum+=nums[r];
            while(sum>=target){//>=RIGHT:不能只是大于的时候才记录长度,因为可能出现留下124忽略34的情况
                result = min(result, r-l+1);
                sum-=nums[l];
                l++;//【这三句顺序必须这样,否则会提前更新】
            }
            r++;
        }
        return result == INT_MAX? 0: result;WRONG= RIGHT==
    }
};

59. 螺旋矩阵

类似二分法,区间开闭一致、扣细节题;
先走一步,探路;
再正式走下一步


class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> nums(n, vector<int>(n,0));
        vector<vector<int>>dic  {{0,1},{1,0},{0,-1},{-1,0}};//写 = 也ok
        int x=0, y = 0;
        int dic_n = 0;
        int newx = 0, newy = 0;

        for(int i = 1; i<=n*n; i++){
            nums[x][y]=i;
            int newx=x+dic[dic_n][0];
            int newy=y+dic[dic_n][1];
            if(newx>=n || newy>=n || newx<0 ||newy<0 || nums[newx][newy]!=0 ) dic_n = (dic_n+1)%4;/不可以是++!!!!
            //不可以 else { x = newx;  y = newy;  }只是更新方向,不更新方向的话还是需要维持原方向继续前进的
            x = x+dic[dic_n][0];
            y = y+dic[dic_n][1];
        }
        return nums;
    }
};

自己写的真·暴力解法

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> nums(n, vector<int>(n,0));
        vector<vector<int>>dic {{0,1},{1,0},{0,-1},{-1,0}};//= ok
        int x=0, y = 0;//WRONG INT X, Y=0:只有y被赋值了!
        int dic_n = 0;
        //for(int i = 1; i<=n; i++){
        int i = 1;
        //cout<<dic[0][0]<<"   "<<dic[0][1];
        while(i<=n*n){//WRONG N
            while(y<=n-1 && nums[x][y]==0){//while 
                nums[x][y]=i;
                x+=dic[0][0];
                y+=dic[0][1];
                i++;
            }
            x++;y--;
            while(x<=n-1 && nums[x][y]==0){
                nums[x][y]=i;
                x+=dic[1][0];
                y+=dic[1][1];
                i++;
            } 
            x--;y--;
            while(y>=0 && nums[x][y]==0){
                nums[x][y]=i;
                x+=dic[2][0];
                y+=dic[2][1];
                i++;
            }
            x--; y++;
            
            while(x>0 && nums[x][y]==0){
                nums[x][y]=i;
                x+=dic[3][0];
                y+=dic[3][1];
                i++;
            }  
            x++;y++;        
// cout<<x<<"  "<<y<<endl;break;
        }
        return nums;
    }
};

21天数据结构基础

136.只出现一次的数字

^这个符号代表异或运算,不是幂!
异或运算特点:
a⊕0=a;
a⊕a=0;
满足交换律和结合律。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret= 0;
        for(int i = 0; i < nums.size(); i++){
            ret = nums[i] ^ ret;
        }
        return ret;

    }
};

15.三数之和

有两个错误点:
①必须使用双指针,否则三重遍历会导致超时;
②双指针的while判断必须是>0,这个目前还不理解!为啥不能是!=0啊[○・`Д´・ ○]

// // // 三指针核心是,指针不是真“指针”,只是一个标记
class Solution{ //-4 -1 -1 0 1 2
    public:vector<vector<int>> threeSum(vector<int>& nums){
        int n = nums.size();
        int first = 0, second = 0, third = nums.size()-1;
        sort(nums.begin(), nums.end());//整个算法能够成立,最重要的一步!!!
        vector<vector<int>> ans;
        for(first = 0; first < n ; first++){
            if (first > 0 && nums[first] == nums[first-1]) continue;
            third = n-1 ;
            for (second = first + 1; second < n; second++){
                if (second > first + 1 && nums[second] == nums[second-1]) continue;// 重复↑条件
//三重循环时间复杂度N^3!!不可取!
                // for (third = n-1 ; third > second; --third){///-1
                //     if (nums[first] + nums[second] + nums[third] == 0) {
                //         ans.push_back({nums[first] , nums[second] , nums[third]});
                //         break;///
                //     }
                // }
                while (second < third && nums[first] + nums[second] + nums[third] > 0) {
                    --third;
                }           
                if (second == third)  break;
                if (nums[first] + nums[second] + nums[third] == 0) ans.push_back({nums[first], nums[second], nums[third]});
                
            }
        }
        return ans;
    }
};
/*这个方法就是我们常说的「双指针」,当我们需要枚举数组中的两个元素时,如果我们发现随着第一个元素的递增,第二个元素是递减的,那么就可以使用双指针的方法,将枚举的时间复杂度从 O(N^2)减少至O(N)。*/

75.颜色分类

/* 特色是只有012三个值,本来想用对比的
虽然不能用sort但能用swap呀!
函数参数的&必须必须加上!!!*/
class Solution{
    public:
    void sortColors(vector<int>& nums){
        int ptr = 0, n = nums.size();
        for (int i =0; i < n; i ++){
            if (nums[i]== 0){              
                swap(nums[i], nums[ptr]);
                ptr++;
            }
        }
        for (int i =0; i < n; i ++){
            if (nums[i]== 1){
                swap(nums[i], nums[ptr]);
                ptr++;
            }
        }
    }
};

56.合并区间

自己的做法采用了一个额外计数j导致容易溢出,官答的方法是:
①采用back()函数直达vector< int >最后的元素
②用!merged.size() || merged.back()[1] < L的或逻辑,避免intervals和merged重合
③一个区间的表示方法中只有两个元素,因此表示成L/R即可,不需要用j计数
④貌似不可以用intervals[i].begin()表示intervals[i][0],不知为何

// class Solution {
// public:
//     vector<vector<int>> merge(vector<vector<int>>& intervals) {
//         if (intervals.size() == 0) {
//             return {};
//         }
//         sort(intervals.begin(), intervals.end());
//         vector<vector<int>> merged;
//         for (int i = 0; i < intervals.size(); ++i) {
//             int L = intervals[i][0], R = intervals[i][1];
//             if (!merged.size() || merged.back()[1] < L) {
//                 merged.push_back({L, R});
//             }
//             else {
//                 merged.back()[1] = max(merged.back()[1], R);
//             }
//         }
//         return merged;
//     }
// };
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution{
    public: 
    vector<vector<int>> merge( vector<vector<int>>& intervals){
        vector<vector<int>> merged;
        if (intervals.size()== 0) return{};
        sort(intervals.begin(), intervals.end());
        for(int i = 0, j = 0; i < intervals.size(); i++){
            if (i == 0 ) {
                //merged.push_back(intervals[i]);
                merged.push_back({intervals[i][0] , intervals[i][1]});
            }
            //if (intervals[i].begin() > merged[j].end()) {
            else if (intervals[i][0] > merged[j][1]) {
                merged.push_back({intervals[i][0] , intervals[i][1]});
                j++;
            }
            else {
                merged[j][1] = max(merged[j][1], intervals[i][1]);
                cout<< j << merged[j][1] << intervals[i][1] << endl;
            }

        }


        return merged;
    }
};


快速排序

【https://www.runoob.com/w3cnote/quick-sort.html】

#include<bits/stdc++.h>
using namespace std;
void quick_sort(vector<int>& s, int l, int r)
{
    if (l < r)
    {
        //Swap(s[l], s[(l + r) / 2]); 
        //将中间的这个数和第一个数交换 参见注1:
        //有的书上是以中间的数作为基准数的,要实现这个方便非常方便,直接将中间的数和第一个数进行交换就可以了。
        
        int i = l, j = r, x = s[l];
        while (i < j)
        {
            while(i < j && s[j] >= x) // 从右向左找第一个小于x的数
                j--;  
            if(i < j) 
                s[i++] = s[j];
            
            while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
                i++;  
            if(i < j) 
                s[j--] = s[i];
        }
        s[i] = x;
        quick_sort(s, l, i - 1); // 递归调用 
        quick_sort(s, i + 1, r);//有点类似“中左右”
    }
}
int main(){
    int n;
    cin>>n;
    vector<int>a(n,0);
    for(int i = 0; i<n; i++) cin>>a[i];
    quick_sort(a, 0, n-1);
    for(int i = 0; i<n; i++){
        if(i==0)cout<<a[i];
        else cout<<" "<<a[i];
    }
    cout<<endl;
    return 0 ;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值