LeetCode刷题笔记Day1-Day2

题目分析

题目1

3. 无重复字符的最长子串

分析

双指针,i往右移,j往左移,长度即为i-j+1,当遇到重复的字符串的时候让i和j相等

代码

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char,int>map;//记录字符出现的次数
        int res=0;
        for(int i=0,j=0;i<s.size();i++){
            map[s[i]]++;
            while(map[s[i]]>1){
                map[s[j]]--;
                j++;
            }
            res=max(res,i-j+1);
        }
        return res;
    }
};

题目2

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

分析

二分

代码

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if(nums.size()==0)return{-1,-1};
        int l=0,r=nums.size()-1;
        vector<int>res;
        while(l<r){
            int mid=l+r>>1;
            if(nums[mid]>=target)r=mid;
            else l=mid+1;
        }

        if(nums[r]==target){
            res.push_back(r);
            r=nums.size()-1;
            while(l<r){
                int mid=l+r+1>>1;
                if(nums[mid]<=target)l=mid;
                else r=mid-1;
            }
            res.push_back(r);
        }else{
            res={-1,-1};
        }
        return res;  
    }
};

题目3

844. 比较含退格的字符串

分析

入栈出栈

代码

class Solution {
public:
    string getString(string &s){
        string res;
        for(int i=0;i<s.size();i++){
            if(s[i]!='#')res+=s[i];
            else if(!res.empty())res.pop_back();
        }
        return res;
    }

    bool backspaceCompare(string s, string t) {
        string s1=getString(s);
        string t1=getString(t);
        return s1==t1;
    }
};

题目4

374. 猜数字大小

分析

简单二分,要考虑数据溢出

代码

/** 
 * Forward declaration of guess API.
 * @param  num   your guess
 * @return 	     -1 if num is lower than the guess number
 *			      1 if num is higher than the guess number
 *               otherwise return 0
 * int guess(int num);
 */

class Solution {
public:
    int guessNumber(int n) {
        long long l=1,r=n;
        while(l<r){
            long long mid=(l+r)/2;
            if(guess(mid)==-1)r=mid;
            else if(guess(mid)==1)l=mid+1;
            else return mid;
        }
        return l;
    }
};

题目5

852. 山脉数组的峰顶索引

分析

二分,当后边大于前面一个数,说明是递增的,左边界右移,反正右边界左移

代码

class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr) {
        int l=0,r=arr.size()-1;
        while(l<r){
            int mid=(l+r+1)/2;
            if(arr[mid]>arr[mid-1])l=mid;
            else r=mid-1;
        }
        return l;
    }
};

题目6

1385. 两个数组间的距离值

分析

暴力模拟,二分没想到

答案

class Solution {
public:
    int findTheDistanceValue(vector<int>& arr1, vector<int>& arr2, int d) {
        int res=0;
        for(auto a1: arr1){
            int cnt=0;
            for(auto a2:arr2){
                if(abs(a2-a1)<=d){
                    break;
                }
                cnt++;
            }
            if(cnt==arr2.size()){
                res++;
            }
        }
        return res;
    }
};

看了一下题解,原来是用二分判断是否在该区间

class Solution {
public:
    int findTheDistanceValue(vector<int>& arr1, vector<int>& arr2, int d) {
        sort(arr2.begin(),arr2.end());
        int ans=0;
        for(auto a1:arr1){
            int low=a1-d;
            int high=a1+d;
            if(!search(arr2,low,high)){
                ans++;
            }
        }
        return ans;
    }

    bool search(vector<int>&arr,int low,int high){
        int l=0,r=arr.size()-1;
        while(l<=r){
            int mid=(l+r)/2;
            if(arr[mid]>=low&&arr[mid]<=high)return true;
            else if(arr[mid]<low)l=mid+1;
            else if(arr[mid]>high) r=mid-1;
        }
        return false;
    }
};

题目7

13. 罗马数字转整数

分析

模拟,当后面一位大于当前的时候,减去当前代表的数字

代码

class Solution {
public:
    int romanToInt(string s) {
        unordered_map<char,int>map{{'I',1},{'V',5},{'X',10},{'L',50},{'C',100},{'D',500},{'M',1000}};
        int res=0;
        for(int i=0;i<s.size();i++){
            if(map[s[i]]<map[s[i+1]])res-=map[s[i]];
            else res+=map[s[i]];
        }
        return res;
    }
};

题目8

796. 旋转字符串

分析

判断\(str\)的长度与goal是否相等且\(s+s\)是否包含\(goal\)即可,这题可以拿来练练\(KMP\)(雾)

代码

class Solution {
public:
    bool KMP(string str,string pattern){
        int m=str.size();
        int n=pattern.size();

        str=" "+str;
        pattern=" "+pattern;
        vector<int>next(n+1,0);
        for(int i=2,j=0;i<n+1;i++){
            while(j>0&&pattern[i]!=pattern[i+1])j=next[j];
            if(pattern[i]==pattern[j+1])j++;
            next[i]=j;
        }

        for(int i=1,j=0;i<m+1;i++){
            while(j>0&&str[i]!=pattern[j+1])j=next[j];
            if(str[i]==pattern[j+1])j++;
            if(j==n)return true;
        }
        return false;
    }

    bool rotateString(string s, string goal) {
        return s.size()==goal.size()&&KMP(s+s,goal);
    }
};

题目9

954. 二倍数对数组

分析

哈希+排序

代码

class Solution {
public:
    bool canReorderDoubled(vector<int>& arr) {
        unordered_map<int,int>map;
        sort(arr.begin(),arr.end());
        for(auto a:arr){
            if(a>=0&&a%2==0&&map.count(a/2)){
                map[a/2]--;
                if(map[a/2]==0)map.erase(a/2);
            }else if(a<0&&map.count(a*2)){
                map[a*2]--;
                if(map[a*2]==0)map.erase(a*2);
            }else{
                map[a]++;
            }
        }
        return map.size()==0;
    }
};

题目10

154. 寻找旋转排序数组中的最小值 II

分析

153. 寻找旋转排序数组中的最小值不同的是情况有可能变成了这种,所以要先去掉右边的重复元素,让二分的区间变成严格单调递增,转化为153. 寻找旋转排序数组中的最小值,在进行二分image-20220407101428572

代码

class Solution {
public:
    int findMin(vector<int>& nums) {
        int l=0,r=nums.size()-1;
        //让二分区间严格单调递增
        while(l<r&&nums[r]==nums[0])r--;
        //判断是否升序
        if(nums[l]<=nums[r])return nums[0];
        while(l<r){
            int mid=l+r>>1;
            if(nums[mid]<nums[0])r=mid;
            else l=mid+1;
        }
        return nums[l];
    }
};

题目11

136. 只出现一次的数字

分析

位运算

  1. 交换律:\(a\) ^$ b$ ^ \(c <=> a\) ^ \(c\) ^$ b$
  2. 任何数与\(0\)异或为任何数 \(0\) ^ \(n => n\)
  3. 相同的数异或为\(0\): \(n\) ^ \(n => 0\)

代码

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int res=0;
        for(auto x:nums){
            res=res^x;
        }
        return res;
    }
};

题目12

137. 只出现一次的数字 II

分析

还是位运算( 自己只会哈希,没想到),将评论摘录如下

  • 摘录1:

    【笔记】网上大佬曾经说,如果能设计一个状态转换电路,使得一个数出现3次时能自动抵消为0,最后剩下的就是只出现1次的数。

    开始设计:一个二进制位只能表示0或者1。也就是天生可以记录一个数出现了一次还是两次。

    • \(x\) ^ \(0\) = \(x\);

    • \(x\) ^ \(x\) = \(0\);

    要记录出现3次,需要两个二进制位。那么上面单独的x就不行了。我们需要两个变量,每个变量取一位:

    • \(ab\) ^ \(00\) = \(ab\);

    • \(ab\) ^ \(ab\) = \(00\);

    这里,ab都是32位的变量。我们使用a的第k位与b的第k位组合起来的两位二进制,表示当前位出现了几次。也就是,一个8位的二进制x就变成了16位来表示。

    • \(x = x[7] x[6] x[5] x[4] x[3] x[2] x[1] x[0]\)
    • \(x = (a[7]b[7]) (a[6]b[6]) ... (a[1]b[1]) (a[0]b[0])\)

    于是,就有了这一幕....

    它是一个逻辑电路,ab变量中,相同位置上,分别取出一位,负责完成00->01->10->00,也就是开头的那句话,当数字出现3次时置零。

    int singleNumber(vector<int>& nums) {
         int a = 0, b = 0;
         for (auto x : nums) {
             b = (b ^ x) & ~a;
             a = (a ^ x) & ~b;
         }
         return b;
     }
    

    补充1:2019/4/13 感谢@uhauha2929 @CodeBaby @Trrific 等人在评论中提到,代码中ab写反了的问题,现已更正。

    补充2:2019/5/26 @金木盐 在楼下补充了两组例子,希望能更好解释3次时自动抵消归零。

    • \(x\) & \(~x\) = \(0\);
    • \(x\) & \(~0\) = \(x\);
  • 摘录2:

    class Solution {
    public:
        int singleNumber(vector<int>& nums) {
            int a = 0, b = 0;
            for (auto num : nums)
            {
                a = (a ^ num) & ~b;
                b = (b ^ num) & ~a;
            }
            return a;
        }
    };
    

    代码参考热评。解释下:

    假设有一个数为\(x\), 那么则有如下规律:

    • $0 \(^\) x = x$,

    • \(x\) ^ \(x = 0\)

    • \(x\&\) ~\(x = 0\),

    • \(x\&\) ~\(0 =x\);

    那么就是很好解释上面的代码了。一开始\(a = 0\), \(b = 0\);

    1. \(x\)第一次出现后,\(a = (a\) ^ \(x) \&\) ~\(b\)的结果为 \(a = x\), \(b = (b\) ^ \(x) \&\) ~\(a\)的结果为此时因为\(a = x\)了,所以\(b = 0\)
    2. \(x\)第二次出现:\(a = (a\) ^$ x) &$ ~\(b\), \(a = (x\) ^$ x) & $~\(0\), \(a = 0\); \(b = (b\) ^ \(x) \&\) ~\(a\) 化简, $b = (0 \(^\) x) &$ ~\(0\) ,\(b = x\);
    3. \(x\)第三次出现:\(a = (a\) ^ \(x) \&\) ~\(b\)\(a = (0\) ^ \(x) \&\) ~\(x\) ,\(a = 0\);$ b = (b$ ^ \(x) \&\) ~\(a\) 化简, \(b = (x\) ^$ x) &$ ~\(0\) , \(b = 0\);所以出现三次同一个数,\(a\)\(b\)最终都变回了\(0\).
    • 只出现一次的数,按照上面x第一次出现的规律可知\(a = x\),$ b = 0\(;因此最后返回\)a$

原解

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_map<int,int>map;
        for(auto num:nums)map[num]++;
        for(auto num:nums){
            if(map[num]==1)return num;
        }
        return -1;
    }
};

位运算

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int a=0,b=0;
        for(auto num:nums){
            a=(a^num)&~b;
            b=(b^num)&~a;
        }
        return a;
    }
};

题目13

分析

情人节的单身虐狗题,以前在b站看过题解,思路是先把最后一个补齐,然后两两分组,会划分为前面的数等于后面的数以及前面的数不等于后面的数两个区间,然后直接二分

代码

class Solution {
public:
    int singleNonDuplicate(vector<int>& nums) {
        nums.push_back(nums.back()+1);
        int l=0,r=nums.size()/2-1;
        while(l<r){
            int mid=l+r>>1;
            if(nums[mid*2]!=nums[mid*2+1])r=mid;
            else l=mid+1;
        }
        return nums[r*2];
    }
};

题目14

分析

第一感觉就是全排列,但是要在第k次结束递归,不然会超时。(执行用时:760 ms, 在所有 C++ 提交中击败了6.72%的用户,我是fw呜呜呜)

代码

class Solution {
public:
    int n,status[10],cnt=0;
    bool used[10];
    string res;

    void dfs(int u,int k){
        if(u>n){
            cnt++;
            if(cnt==k){
                for(int i=1;i<=n;i++)res+=to_string(status[i]);
                return;
            }
            return;
        }

        for(int i=1;i<=n;i++){
            if(!used[i]){
                status[u]=i;
                used[i]=true;
                dfs(u+1,k);
                status[u]=0;
                used[i]=false;
            }
        }
    }

    string getPermutation(int m, int k) {
        n=m;
        dfs(1,k);
        return res;
    }
};
posted @ 2022-04-07 11:36  灰之魔女伊蕾娜  阅读(43)  评论(0)    收藏  举报