数据结构基础---【数组/字符串/滑动窗口/矩阵/哈希表/区间】

数组/字符串

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

【26】删除有序数组中的重复项

方法一:申请额外空间
时间o(n),空间o(1)

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int left = 0;
        int right = 0;
        set<int> tmp_set;
        vector<int> tmp;
        for(int i =0;i<nums.size();i++){
            if(tmp_set.find(nums[i]) == tmp_set.end())
            {
                tmp_set.insert(nums[i]);
                tmp.push_back(nums[i]);
            }
        }
        
        for(int i =0;i<tmp.size();i++){
            nums[i] = tmp[i];
        }
        return tmp.size();
    }
};

双指针,原地修改:

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int n = nums.size();
        if(0 == n){
            return 0;
        }
        int fast = 1,slow = 1;
        while(fast<n){
            if(nums[fast] != nums[fast-1]){
                nums[slow] = nums[fast];
                slow++;
            }
            fast++;
        }
        return slow;
    }
};

【80】删除有序数组中的重复项II

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

class Solution {
public:
    //原地修改数组只能用快慢数组进行覆盖
    //并且数组是有序的,所以只用考虑两个之间是否是相同的
    int removeDuplicates(vector<int>& nums) {
        int res =0;
        int n = nums.size();    
        if(n <= 2) return n;

        int slow = 2,fast =2;//slow指针,改造后的数组长度
        while(fast<n){
            if(nums[slow -2] != nums[fast]){
                nums[slow] = nums[fast];
                slow++;
            }
            fast++;
        }
        return slow;
    }
};

【88】合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

从数组尾部开始算tail指针,然后一个nums1 和 ptr1 和 nums2 的ptr2的指针分别移动。

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        //不用额外的空间 O(1) 从后做指针
        //时间复杂度 O(M+N)
        int p1 = m-1,p2 = n -1;//两个数组的
        int tail = m+n-1;//从后遍历的指针
        int cur;
        while (p1>=0 || p2>=0){
            if(p1 == -1){//p1已经遍历完了
                cur = nums2[p2--];
            }else if(p2 == -1){//p2已经遍历完了
                cur = nums1[p1--];
            }else if(nums1[p1] > nums2[p2]){//把nums1复制进去
                cur = nums1[p1--];
            }else{
                cur = nums2[p2--];
            }
            nums1[tail--] = cur;
        }

    }
};

双指针

【15】三数之和

(部分用例,超出时间限制…)

class Solution {
public:
    int compare_vec(vector<int>& nums1,vector<vector<int>>& nums2){
        for(int i = nums2.size()-1;i>=0;i--){//一个向量一个向量比
            if(nums1[0] == nums2[i][0]){
                if(nums1[1] == nums2[i][1] && nums1[2] == nums2[i][2] ){
                    return 1;
                }
            }else{
                return 0;
            }
        }
        return 0;
    }
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;
        int n = nums.size();
        if( 0 ==n )return res;
        int count = 0;
        //排序  
        sort(nums.begin(),nums.end());

        //确定三元组
        for(int i =0;i<n;i++){
            for(int j = i+1;j<n;j++){
                for(int k = j+1;k<n;k++){
                    if(nums[i]+nums[j]+nums[k] == 0)
                    {
                        vector<int> tmp = vector<int>{nums[i],nums[j],nums[k]};
                        if(count != 0 && compare_vec(tmp,res)){
                            continue;
                        }
                        res.push_back(vector<int>{nums[i],nums[j],nums[k]});
                        count++;
                    }
                }
            }
        }
        return res;
    }
};

双指针:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;//定义返回数组
        sort(nums.begin(),nums.end());//对数组进行排序
        for(int i =0;i<nums.size();i++){//遍历已经排序好的数组
            if(nums[i]>0){//i遍历到>0的数,那么后面相加肯定大于0
                return res;//返回res
            }
           // 去重a
            if(i>0 && nums[i] == nums[i-1]){
                continue;
            }
            int right = nums.size()-1;
            int left = i+1;
            while(right>left){
                if(nums[i]+nums[left]+nums[right] >0 ){
                    right--;
                }
                else if(nums[i]+nums[left]+nums[right] <0){
                    left++;
                }
                else{// =0的情况
                    res.push_back(vector<int>{nums[i],nums[left],nums[right]});
                    
                    //去重bc
                   while (right > left && nums[right] == nums[right - 1]) right--;
                   while (right > left && nums[left] == nums[left + 1]) left++;
                    left++;//为下一次while做准备
                    right--;
                }
            }
        }
        return res;
    }
};

滑动窗口

矩阵

矩阵注意下标的选取,映射。

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
      // 行集合
        unordered_set<char> row_set[9];
        // 列集合
        unordered_set<char> col_set[9];
        // 3x3宫格集合
        unordered_set<char> box_set[9];

        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                char num = board[i][j];
                //跳过空格
                if (num != '.') {
                    // 检查行
                    if (row_set[i].find(num) != row_set[i].end()) return false;
                    row_set[i].insert(num);
                    // 检查列
                    if (col_set[j].find(num) != col_set[j].end()) return false;
                    col_set[j].insert(num);
                    // 检查3x3宫格
                    int boxIndex = (i / 3) * 3 + j / 3;//注意这个映射
                    if (box_set[boxIndex].find(num) != box_set[boxIndex].end()) return false;
                    box_set[boxIndex].insert(num);
                }
            }
        }
        return true;
    }
      
};

哈希表

区间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值