LeetCode算法C++刷题笔记Day-01

一、算法基础(主题:二分查找)

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

  • 题目描述是:给定一个升序数组,然后找到元素在数组中的开始与结束位置,不存在元素则返回[-1, -1]
  • 解题思路肯定是双指针,通过与middle值的比较,不断缩小搜索范围,找到第一个等于target的index,以及第一个大于target的index再减一
  • 二分查找模板(针对升序数组),left = 0,right = n-1,找target的左边界则设mid = left + right >> 1,满足>=target则right = mid;找右边界则设mid = left + right + 1 >> 1,满足<=target则left = mid。
vector<int> searchRange(vector<int>& nums, int target) {
    vector<int> ans = vector(2, -1);
    int len = (int)nums.size();

    if(len == 0)return ans;

    int start = 0, end = len-1;
    while(start<end){
        int mid = (start + end) >> 1;//找target的左边界
        if(nums[mid]>=target){
            end = mid;
        }else {
            start = mid + 1;
        }
    }
    if(nums[end]!=target) return ans;
    ans[0] = end;

    start = 0, end = len-1;
    while(start<end){
        int mid = (start + end + 1) >> 1;//找target的右边界
        if(nums[mid]<=target){
            start = mid;
        }else{
            end = mid - 1;
        }
    }
    ans[1] = end;

    return ans;
}

2.搜索旋转排序数组(Q33)

  • 题目描述:给定一个不重复值的升序数组,再从某个位置进行切割后重新拼接(即旋转),搜索目标target的index
  • 思路:数组由两个有序的部分组成,而每次与mid比较的时候,都选择在有序的部分进行即可
int search(vector<int>& nums, int target) {
    int len = (int)nums.size();
    int left = 0, right = len - 1;
    while(left<=right){
        int mid = (left + right) >> 1;
        if(nums[mid]==target)return mid;
        if(nums[0]<=nums[mid]){
            //此时左半部分是有序的
            //检查左侧最小值是否小于target,大于则跳到右侧
            if(nums[0]<=target&&nums[mid]>target){
                right = mid-1;
            }else{
                left = mid+1;
            }
        }else{
            //此时右半部分是有序的
            //检查右半部分最大值是否大于target,小于则跳到左侧
            if(nums[len-1]>=target&&nums[mid]<target){
                left = mid + 1;
            }else{
                right = mid -1;
            }
        }
    }
    return -1;
}

3.搜索二维矩阵(Q74)

  • 题目描述:编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值
  • 思路:先判断每行的首个元素,找定行区间,再进行二分查找
bool searchMatrix(vector<vector<int>>& matrix, int target) {
    int col_len = (int)matrix.size();
    int begin = col_len-1;
    for(int i=0;i<col_len;i++){
        if(matrix[i][0]>target){
            begin = i - 1;
            break;
        }
    }
    if(begin<0)return false;
    int left = 0, right = (int)matrix[begin].size() - 1;
    while (left<=right){
        int mid = (left+right)/2;
        if(matrix[begin][mid]==target)return true;
        if(matrix[begin][mid]>target){
            right = mid-1;
        }else{
            left = mid+1;
        }
    }
    return false;
}

二、数据结构(主题:数组)

1.只出现一次的数字(Q136)

  • 题目描述:给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
  • 解题思路:
  • 绝中绝——异或运算,把所有数进行异或运算,最终结果即为答案
int singleNumber(vector<int>& nums) {
    int ans = 0;
    for(int num : nums){
        ans ^= num;
    }
    return ans;
}

2.多数元素(Q169)

  • 题目描述:给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
  • 解题思路:1. 使用哈希表进行统计 2. Boyer-Moore 投票算法
  • 关于思路二——评论区的一种理解方式:
  • 假设整个数组的众数记做a,则最初的数组中a的数量大于其余所有数。当采用count计数的时候有两种情况:
  • 1)假设candidate等于a,则当count从1变为0的过程,此区间内a的数量等于其余数的数量,因此以count=0为分界线,数组右端部分的众数仍然为a
  • 2)假设candidate不等于a,则当count从1变为0的过程, 此区间内a的数量小于等于其余数的数量,因此以count=0为分界线,数组右端部分的众数仍然为a
  • 因此,以count=0可以将整个原始数组分为若干部分,count=0右端部分的数组中的众数永远是a,最终必然会筛选出a
int majorityElement(vector<int>& nums) {
    //solution 1
    unordered_map<int,int> map;
    int ans = 0, count=0;
    for(int num:nums){
        map[num]++;
        if(map[num]>count){
            count = map[num];
            ans = num;
        }
    }
    return ans;

    //solution 2
    int candidate = -1, count=0;
    for(int num:nums){
        if(num==candidate){
            count++;
        }else{
            count--;
        }
        if(count<0){
            candidate = num;
            count = 1;
        }
    }
    return candidate;
}

3.三数之和(Q15)

  • 题目描述:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
vector<vector<int>> threeSum(vector<int>& nums) {
    int size = nums.size();
    if(size<3) return{};

    vector<vector<int>> ans;
    sort(nums.begin(),nums.end());
    for(int i=0;i<size;i++){
        if(nums[i]>0)return ans;
        if(i>0&&nums[i]==nums[i-1])continue;
        int left = i+1, right = size -1;
        while(left<right){
            if((nums[left]+nums[right])>-nums[i])right--;
            else if((nums[left]+nums[right])<-nums[i])left++;
            else{
                ans.push_back(vector<int>{nums[i],nums[left],nums[right]});
                left++;
                right--;
                while(left<right&&nums[left]==nums[left-1])left++;
                while(left<right&&nums[right]==nums[right+1])right--;
            }
        }
    }

    return ans;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值