刷题笔记(4)---数组

数组

二级目录

二分查找

34. 在排序数组中查找元素的第一个和最后一个位置
class Solution {
public:
    int binarySearch(vector<int>& nums, int target, bool lower)
    {
        int l = 0, r = nums.size()-1, mid;
        int result = nums.size();
        while(l <= r)
        {
            mid = l + (r - l)/2;

            if((lower && nums[mid] >= target) || (nums[mid] > target)) 
            { 
                result = mid; 
                r = mid - 1; 
            }
            else 
            { 
                l = mid + 1; 
            }
        }
        return result;
    }

    vector<int> searchRange(vector<int>& nums, int target) {
        if (nums.empty())  return vector<int> {-1, -1};

        int leftIdx = binarySearch(nums, target, true);
        int rightIdx = binarySearch(nums, target, false) - 1;
        if (leftIdx <= rightIdx && rightIdx < nums.size() && nums[leftIdx] == target && nums[rightIdx] == target) {
            return vector<int>{leftIdx, rightIdx};
        } 

        return vector<int> {-1, -1};
    }
};

自主写法,参考数据结构与算法之美!

class Solution {
public:
    int binarySearch(vector<int>& nums, int target, bool flag)
    {
        int l = 0, r = nums.size()-1, mid;
        int result = nums.size();
        while(l <= r)
        {
            mid = l + (r - l)/2;

            if(nums[mid] > target)
            { 
                r = mid - 1; 
            }
            else if(nums[mid] < target)
            { 
                l = mid + 1; 
            }
            else
            {
                if(flag)
                {
                    if(mid == 0 || nums[mid - 1] != target) { return mid; }
                    else { r = mid - 1; }
                }
                else
                {
                    if(mid == nums.size() - 1 || nums[mid + 1] != target) { return mid; }
                    else { l = mid + 1; }
                }
            }
        }
        return -1;
    }

    vector<int> searchRange(vector<int>& nums, int target) {
        if (nums.empty())  return vector<int> {-1, -1};

        int leftIdx = binarySearch(nums, target, true);
        int rightIdx = binarySearch(nums, target, false);
        if (leftIdx <= rightIdx && rightIdx < nums.size() && nums[leftIdx] == target && nums[rightIdx] == target) {
            return vector<int>{leftIdx, rightIdx};
        } 

        return vector<int> {-1, -1};
    }
};
查找第一个大于等于给定值的元素
public int bsearch(int[] a, int n, int value) {
  int l = 0;
  int r = n - 1;
  while (l <= r) {
    int mid =  l + ((r - l) >> 1);
    if (a[mid] >= value) {
      if ((mid == 0) || (a[mid - 1] < value)) return mid;
      else r = mid - 1;
    } else {
      l = mid + 1;
    }
  }
  return -1;
}

查找最后一个小于等于给定值的元素
public int bsearch7(int[] a, int n, int value) {
  int l = 0;
  int r = n - 1;
  while (l <= r) {
    int mid =  l + ((r - l) >> 1);
    if (a[mid] > value) {
      r = mid - 1;
    } else {
      if ((mid == n - 1) || (a[mid + 1] > value)) return mid;
      else l = mid + 1;
    }
  }
  return -1;
}

69. x 的平方根
class Solution {
public:
    int mySqrt(int x) {
        int l=0, r=x, ans = -1;
        int mid;
        while(l <= r)
        {
            mid = l + (r - l) / 2;
 
            if((long long)mid * mid <= x) { ans = mid; l = mid + 1; }
            else { r = mid - 1; }
        }
        return ans;       
    }
};
带有精度怎么考虑?
367. 有效的完全平方数
class Solution {
public:
    bool isPerfectSquare(int num) {
        int l=0, r=num;
        int mid;
        while(l <= r)
        {
            mid = l + (r - l) / 2;
            if((long long )mid * mid > num) { r = mid - 1; }
            else if((long long)mid * mid < num) { l = mid + 1; }
            else { return true; }
        }
        return false;
    }
};
33. 搜索旋转排序数组(×✓)
class Solution {
public:
    int search(vector<int>& nums, int target) {

        int l=0, r=nums.size()-1;
        while(l <= r)
        {
            int mid = l + (r - l) / 2;
            if(nums[mid] == target) { return mid;  }

            if(nums[l] <= nums[mid])
            {
                if(nums[l] <= target && target < nums[mid]) 
                {  r = mid - 1; }
                else 
                { l = mid + 1; }
            }
            else
            {
                if(nums[mid] < target && target <= nums[r])
                { l = mid + 1; }
                else 
                { r = mid - 1; }
            }
        }
        return -1;
    }
};
81. 搜索旋转排序数组 II(√)
class Solution {
public:
    bool search(vector<int>& nums, int target) {
        int l=0, r=nums.size()-1;

        while(l <= r)
        {
            int mid = l + (r - l) / 2;
            if(nums[mid] == target) { return true; }

            if(nums[l] < nums[mid])
            {
                if( nums[l] <= target && target < nums[mid])
                    r = mid - 1;
                else
                    l = mid + 1;
            }
            else if(nums[l] > nums[mid])
            {
                if(nums[mid] < target && target <= nums[r])
                    l = mid + 1;
                else
                    r = mid - 1;
            }
            else
            {
                //skip duplicate one
                l++;
            }
        }

        return false;
    }
};

移除元素

双指针解法。

27. 移除元素(√)
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {

/*
        for(vector<int>::iterator it = nums.begin(); it!=nums.end(); ++it)
        {
            if(*it == val)
            {
                it = nums.erase(it);
                --it;
            }
        }

        return nums.size();
*/        
        int slowIdx = 0;
        int n = nums.size();
        for(int fastIdx=0; fastIdx<n; ++fastIdx)
        {
            if(nums[fastIdx] != val)
            {
                nums[slowIdx++] = nums[fastIdx];
            }
        }

        return slowIdx;
    }
};
26.删除排序数组中的重复项(√)
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if(nums.empty()) { return 0; }

        int slowIdx=0;
        for(int fastIdx=0; fastIdx<nums.size(); ++fastIdx)
        {
            if(nums[fastIdx] != nums[slowIdx])
            {
                nums[++slowIdx] = nums[fastIdx];
            }
        }

        return ++slowIdx;
    }
};
80. 删除有序数组中的重复项 II(×)
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if(nums.size() <= 2) { return nums.size(); }

        int slowIdx = 2;
        for(int fastIdx = 2; fastIdx<nums.size(); ++fastIdx)
        {
            if(nums[fastIdx] != nums[slowIdx-2])
            {
                nums[slowIdx++] = nums[fastIdx];
            }
        }

        return slowIdx;
    }
};
283. 移动零(×)没思路。
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int slow = 0;

        for(int fast = 0; fast<nums.size(); ++fast)
        {
            if(nums[fast] != 0)
            {
                swap(nums[slow], nums[fast]);
                slow++;
            }
        }
    }
};
977. 有序数组的平方

方法一:直接排序。(√)
方法二:双指针。(×)

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++;
            }
            else
            {
                result[k--] = nums[j]*nums[j];
                j--;
            }
        }
        return result;
    }
};
209. 长度最小的子数组(滑动窗口 / 双指针)
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int result = INT_MAX;
        int sum = 0;    // 滑动窗口数值之和
        int subLength = 0;  // 滑动窗口的长度
        int i=0;    // 滑动窗口起始位置
        for(int j=0; j<nums.size(); ++j)
        {
            sum += nums[j];
            // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
            while(sum >= target)
            {
                subLength = j - i + 1;  // 取子序列的长度
                result = result < subLength ? result : subLength;
                // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
                sum -= nums[i++];
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT_MAX ? 0 : result;
    }
};
904. 水果成篮(未学习×)
76. 最小覆盖子串(未学习×)
844. 比较含退格的字符串

方法一:重构字符串

class Solution {
private:
    string build(string str)
    {
        string ret;
        for(auto ch : str)
        {
            if(ch != '#') { ret.push_back(ch); }
            else if(!ret.empty()){ ret.pop_back(); }
        }
        return ret;
    }
public:
    bool backspaceCompare(string s, string t) {
        return build(s) == build(t);
    }
};

方法二:双指针(待学习)

螺旋矩阵

59. 螺旋矩阵 II
class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> result(n, vector<int>(n, 0));

        // 定义每循环一个圈的起始位置
        int startx = 0, starty = 0;
        // 循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
        int loop = n / 2; 
        // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
        int mid = n / 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++)
            {
                result[startx][j] = count++;
            }
            // 模拟填充右列从上到下(左闭右开)
            for(i=startx; i<startx + n - offset; i++)
            {
                result[i][j] = count++;
            }
            // 模拟填充下行从右到左(左闭右开)
            for(; j>starty; j--)
            {
                result[i][j] = count++;
            }
            // 模拟填充左列从下到上(左闭右开)
            for(; i>startx; i--)
            {
                result[i][j] = count++;
            }
            // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            startx++;
            starty++;

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

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

        return result;
    }
};
54. 螺旋矩阵(没懂×)
剑指 Offer 29. 顺时针打印矩阵(没懂×)
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        if(matrix.size() == 0 || matrix[0].size() == 0) { return {}; }

        int rows = matrix.size(), columns = matrix[0].size();
        vector<int> result;
        int left = 0, right = columns - 1, top = 0, bottom = rows - 1;

        while(left <= right && top <= bottom)
        {
            for(int column = left; column <= right; ++column)
            {
                result.push_back(matrix[top][column]);
            }

            for(int row=top+1; row<=bottom; ++row)
            {
                result.push_back(matrix[row][right]);
            }

            if(left < right && top < bottom)
            {
                for(int column = right-1; column > left; --column)
                {
                    result.push_back(matrix[bottom][column]);
                }

                for(int row = bottom; row > top; --row)
                {
                    result.push_back(matrix[row][left]);
                }
            }
            left++;
            right--;
            top++;
            bottom--;
        }
        
        return result;
    }
};
15. 三数之和(双指针解法)

1.先排序
2.基本框架
3.注意去重逻辑

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;

        sort(nums.begin(), nums.end());

        for(int i=0; i<nums.size(); ++i)
        {
        	// 本题是三数之和为零,所以可有这句代码
            if(nums[i] > 0) return result;

			// 注意去重逻辑
            if(i > 0 && nums[i] == nums[i-1]) continue;

            for(int left=i+1, right=nums.size()-1; left<right; )
            {
                int sum = nums[i] + nums[left] + nums[right];
                if(sum > 0) { right--; }
                else if(sum < 0) { left++; }
                else 
                { 
                    result.push_back(vector<int>{nums[i], nums[left], nums[right]}); 
					
					// 注意去重逻辑
                    while(left<right && nums[right] == nums[right-1]) right--;
                    while(left<right && nums[left] == nums[left]+1) left++;

                    right--;
                    left++;
                
                }
            }
        }
        return result;
    }
};
18. 四数之和(双指针解法)

1.先排序
2.基本框架
3.注意去重逻辑

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> result;

        sort(nums.begin(), nums.end());

        for(int i=0; i<nums.size(); ++i)
        {
        	// 注意去重逻辑
            if(i > 0 && nums[i] == nums[i-1]) continue;

            for(int j=i+1; j<nums.size(); ++j)
            {
            	// 注意去重逻辑
                if(j > i+1 && nums[j] == nums[j-1]) continue;

                for(int left=j+1, right=nums.size()-1; left<right; )
                {
                	// 整形溢出问题
                    long long sum = (long long)nums[i] + nums[j] + nums[left] + nums[right];

                    if(sum > target) right--;
                    else if(sum < target) left++;
                    else
                    {
                        result.push_back(vector<int> {nums[i], nums[j], nums[left], nums[right]});
						// 注意去重逻辑
                        while(left < right && nums[right] == nums[right-1]) right--;
                        while(left < right && nums[left] == nums[left+1]) left++;

                        right--;
                        left++;
                    }
                }
            }
        }
        return result;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值