【数据结构/数组】题解+详细备注(共14题)

本文解析了704.二分查找、35.插入位置搜索、34.查找范围等经典问题的解决方案,涉及数据结构中的数组操作,包括排序数组的特殊查询、平方根计算、完全平方数判断及移除重复元素等。通过双指针和滑动窗口技巧,深入探讨了算法效率与实现细节。
摘要由CSDN通过智能技术生成

704.二分查找

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = nums.size();

        int left{},right = n-1;
		// 定义解在:[left,right]中
        while(left <= right){
            int mid = (left + right) >> 1;

            if(nums[mid] == target){
                return mid;
            }else if(nums[mid] > target){
                right = mid-1;
            }else{
                left = mid + 1;
            }
        }

        return -1;
    }
};

35.搜索插入位置

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left{},right = nums.size();
		// 定义解在:[left,right)中
        while(left < right){
            int mid = left + (right - left)/2;
            if(nums[mid] > target){
                right = mid;
            }else if(nums[mid] < target){
                left = mid + 1;
            }else{
                return mid;
            }
        }

        return right;
    }
};

34.在排序数组中查找元素的第一个和最后一个位置

class Solution {
public:
    int getRightBoard(vector<int>& nums, int target){
        int left{},right = nums.size() -1;
        int righBoard{-2};

        while(left <= right){
            int mid = left + (right - left)/2;

            if(nums[mid] <= target){
                left = mid + 1;
                righBoard = left;// 关键是记录最后一个右边界的前一个
            }else{
                right = mid -1;
            }
        }
        
        return righBoard;
    }

    int getLeftBoard(vector<int>& nums, int target){
        int left{},right = nums.size() -1;
        int leftBoard{-2};
		// 定义解在:[left,right]中
        while(left <= right){
            int mid = left + (right - left)/2;
            
            if(nums[mid] >= target){
                right = mid -1;
                leftBoard = right;// 关键是记录最后一个左边界的后一个
            }else{
                left = mid +1;
            }
        }

        return leftBoard;
    }
    vector<int> searchRange(vector<int>& nums, int target) {
        int left{-2},right{-2};

        left = getLeftBoard(nums,target);
        right = getRightBoard(nums,target);

        if(left == -2 || right== -2) return{-1,-1};
		// 由于之前得到的是最后一个右边界的前一个与最后一个左边界的后一个;所以分别+1,-1
        if(right - left > 1) return {left +1,right-1};
        return {-1,-1};
    }
};

69.x的平方根

class Solution {
public:
    int mySqrt(int x) {
        int left{},right = x;
        int ans{};
        // 定义解在:[left,right]中 
        while(left <= right){
            int mid = left + (right - left)/2;
            long long mul = (long long)mid * mid;
            if(mul == x){
                return mid;
            }else if(mul < x){
                ans = mid; // 每次都要记录不符合条件的左侧中的最大值
                left = mid +1;
            }else{
                right = mid - 1;
            }
        }
        return ans;
    }
};

367.有效的完全平方数

class Solution {
public:
    bool isPerfectSquare(int num) {
        int left{1},right = num;
		// 定义解在:[left,right]中 
        while(left <= right){
            int mid = left + (right - left)/2;

            long long mul = (long long)mid*mid;

            if(mul == num){
                return true;
            }else if(mul > num){
                right = mid -1;
            }else {
                left = mid + 1;
            }
        }

        return false;
    }
};

27.移除元素

class Solution {
public:
	// 双指针的应用
    int removeElement(vector<int>& nums, int val) {
        int left{},right{};
        int n = nums.size();

        for(;right < n;++right){
        	// 左指针指向=val值,右指针指向!=val值
            if(nums[right] != val){
                swap(nums[left++],nums[right]);
            }
        }

        return left;
    }
};

26.删除排序数组中的重复项

class Solution {
public:
	// 双指针的应用
    int removeDuplicates(vector<int>& nums) {
        int slowIndex{},fastIndex{1};
		// 左指针指向第二个重复的元素,右指针指向第一个与左指针的元素不重复的元素
        for(;fastIndex < nums.size();++fastIndex){
            if(nums[fastIndex] != nums[fastIndex-1]){
                nums[++slowIndex] = nums[fastIndex];
            }
        }

        return slowIndex+1;
    }
};

283移动零

class Solution {
public:
	// 双指针的应用
    void moveZeroes(vector<int>& nums) {
        int slowIndex{},fastIndex{};
        int n = nums.size();
       	// 左指针指向0,右指针指向非0元素
        for(;fastIndex < n;++fastIndex){
            if(nums[fastIndex] != 0){
                swap(nums[slowIndex++],nums[fastIndex]);
            }
        }
    }
};

844比较含退格的字符串

class Solution {
public:
	// 双指针的应用
    bool backspaceCompare(string s, string t) {
        int nS = s.size();
        int nT = t.size();  

        int indexS = nS-1;
        int indexT = nT-1;
        // 左指针指向s的非#以及被消退的最后一个字符
        // 右指针指向t的非#以及被消退的最后一个字符
        while(indexS >=0 || indexT >=0){
            int countS{};
            int countT{};

            while(indexS >=0){
                if(s[indexS] == '#'){
                    countS++;
                    indexS--;
                }else if(countS > 0){
                    countS--;
                    indexS--;
                }else {
                    break;
                }
            }

            while(indexT >=0){
                if(t[indexT] == '#'){
                    countT++;
                    indexT--;
                }else if(countT > 0){
                    countT--;
                    indexT--;
                }else {
                    break;
                }
            }

            if(indexT >=0 && indexS >=0){
                if(s[indexS] != t[indexT]){
                    return false;
                }
            }else if(indexS >=0 || indexT >=0){
                return false;
            }
            

            --indexT;
            --indexS;
        }

        return true;
    }
};

977有序数组的平方

class Solution {
public:
	// 双指针的应用
    vector<int> sortedSquares(vector<int>& nums) {
        int left{},right = nums.size()-1;
        vector<int> result(nums.size());
        int index =  nums.size()-1;
        // 左指针指向要赋值的新数组最后一个元素,右指针指向原数组最大的元素
        while(left <= right){
            if(abs(nums[left]) > abs(nums[right])){
                result[index--] = nums[left]*nums[left++];
            }else{
                result[index--] = nums[right]*nums[right--];
            }
        }

        return result;
    }
};

209.长度最小的子数组

class Solution {
public:
	// 滑动窗口的应用(也可以理解为双指针的应用)
    int minSubArrayLen(int target, vector<int>& nums) {
        int result = INT_MAX;
        int i{};// 窗口左边界
        int j{};// 窗口右边界
        int sum{};
        int subLength{};
        for(;j<nums.size();++j){
            sum += nums[j];
			// 左边界右移
            while(sum >= target){
                subLength = j-i + 1;
                result = result < subLength ? result : subLength;
                sum-=nums[i++];
            }
        }

        return result == INT_MAX ? 0 : result;
    }
};

904.水果成篮

class Solution {
public:
	// 滑动窗口的应用
    int totalFruit(vector<int>& fruits) {
        int i{};// 窗口左边界
        int j{};// 窗口右边界
        int len{};// 当前采摘数量
        int ans{};// 最大采摘数量
        unordered_map<int,int> mp; // 记录采摘的水果的种类

        for(;j<fruits.size();++j){
            mp[fruits[j]]++;
            len++;
            // 窗口左边界右移
            while(mp.size() > 2){
                mp[fruits[i]]--;
                if(mp[fruits[i]] == 0) mp.erase(fruits[i]);
                len--;
                i++;
            }
			// 更新最大采摘数量
            if(ans < len){
                ans = len;
            }
        }

        return ans;
    }
};

76.最小覆盖子串

class Solution {
public:
	// 滑动窗口的应用
    string minWindow(string s, string t) {
        vector<int> need(128);
		// 记录t中的字符数量
        for(char c : t) need[c]++;
		// 窗口左边界,右边界
        int left{},right{};
        int start{};// 记录最小值的起始位置
        int count = t.size();
        int size = INT_MAX;

        for(;right < s.size();++right){
            char c = s[right];
            // 进行一次匹配
            if(need[c] > 0) count--;
            need[c]--;// 将右边的字符+入窗口内(可以为负值)
			// 当前已经完全匹配到了
            if(count == 0){
                // 缩减窗口(一直缩减到遇到t中的字符位置)
                while(left < right && need[s[left]] < 0){
                    need[s[left++]]++;// 将原窗口内的字符移出窗口
                }
				// 更新最小值
                if(right - left + 1 < size){    
                    size = right - left + 1;
                    start = left;
                }

                need[s[left++]]++;// 左边界右移
                count++;
            }
        }

        return size == INT_MAX ? "" : s.substr(start,size);
    }
};

59.螺旋矩阵II

vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
        int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
        int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
        int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
        int count = 1; // 用来给矩阵中每一个空格赋值
        int offset = 1; // 每一圈循环,需要控制每一条边遍历的长度
        int i,j;
        while (loop --) {
            i = startx;
            j = starty;

            // 下面开始的四个for就是模拟转了一圈
            // 模拟填充上行从左到右(左闭右开)
            for (j = starty; j < starty + n - offset; j++) {
                res[startx][j] = count++;
            }
            // 模拟填充右列从上到下(左闭右开)
            for (i = startx; i < startx + n - offset; i++) {
                res[i][j] = count++;
            }
            // 模拟填充下行从右到左(左闭右开)
            for (; j > starty; j--) {
                res[i][j] = count++;
            }
            // 模拟填充左列从下到上(左闭右开)
            for (; i > startx; i--) {
                res[i][j] = count++;
            }

            // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            startx++;
            starty++;

            // offset 控制每一圈里每一条边遍历的长度
            offset += 2;
        }

        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
        if (n % 2) {
            res[mid][mid] = count;
        }
        return res;
    }

54.螺旋矩阵

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();
        vector<int> ans;

        // 定义边界
        int u = 0;
        int r = n-1;
        int d = m-1;
        int l = 0;

        while(true){
        	// 上行从左到右
            for(int i = l;i <= r;++i) ans.push_back(matrix[u][i]);
            if(++u > d) break;
            // 右列从上到下
            for(int i = u; i<=d;++i) ans.push_back(matrix[i][r]);
            if(--r < l) break;
            // 下行从右到左
            for(int i = r;i>=l;--i) ans.push_back(matrix[d][i]);
            if(--d < u) break;
            // 左列从下到上
            for(int i = d;i>=u;--i) ans.push_back(matrix[i][l]);
            if(++l > r) break;
        }


        return ans;
    }
};

剑指 Offer 29.顺时针打印矩阵

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        if(matrix.size() == 0 ) return {};
        int m = matrix.size();
        int n = matrix[0].size();
        vector<int> result;

        int l{},r{n-1},u{},d{m-1};
        while(true){
            for(int i = l;i <= r;++i) result.emplace_back(matrix[u][i]);
            if(++u > d) break;

            for(int i = u;i<=d;++i) result.emplace_back(matrix[i][r]);
            if(--r < l) break;

            for(int i = r;i>=l;--i) result.emplace_back(matrix[d][i]);
            if(--d < u) break;

            for(int i = d;i>=u;--i) result.emplace_back(matrix[i][l]);
            if(++l > r) break;
        }

        return result;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一二三o-0-O

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值