算法题要重复刷的


前言

算法题有一些困难题,需要反复刷

还有一些技巧性题目,比如位运算

还有什么基础数学的那种,

LCR 138. 有效数字 - 力扣(LeetCode)

LCR 170. 交易逆序对的总数 - 力扣(LeetCode)

思路:一看要求onlogn肯定是归并排序

ps:冒泡排序也能做,但是会超时

我的问题在于:你如何知道合并的两个子数组是排序了的

答:其实就是一个归并排序的过程,只不过在处理期间去计算逆序对,因为你最早是从单个数字开始归并,所以肯定是排序了的

但是这一题和链表归并排序还不一样,有点小区别,你得用temp数组覆盖原来的

class Solution {
    int count=0;
    public int reversePairs(int[] nums) {
            this.count=0;
            mergeSort(nums, 0, nums.length-1);
            return count;
    }

    public void mergeSort(int[]nums,int left,int right)
    {
        if(left>=right)
        {
            return;
        }
        int mid=(left+right)/2;

        mergeSort(nums, left, mid);
        mergeSort(nums, mid+1, right);
        merge(nums, left, mid, right);
    }



    public void merge(int []nums,int left,int mid ,int right)//因为这题给的是数组,不是链表
    {
        int[]temp=new int[right-left+1];//所以需要temp数组,然后来覆盖掉排序前的数组
        int i=left;
        int j=mid+1;
        int t =0;
        while (i<=mid&&j<=right) {
            if(nums[i]<=nums[j])
            {
                temp[t++]=nums[i++];
            }else
            {
                count+=mid-i+1;
                temp[t++]=nums[j++];
            }
        }

        while(i<=mid)
        {
            temp[t++]=nums[i++];
        }

        while (j<=right) {
            temp[t++]=nums[j++];
        }

        for(int k=0;k<temp.length;k++)//把原来的数组覆盖掉
        {
            nums[left+k]=temp[k];
        }
        
    }
}

二进制中1的个数_牛客题霸_牛客网 (nowcoder.com)

public int NumberOf1 (int n) {
    // write code here
     int res=0;
     while(n!=0)
     {
        res++;
        n&=(n-1);
     }
     return res;
}

记住:n&(n-1)可以消除用二进制表示的n里面最后一位的1

不用加减乘除做加法_牛客题霸_牛客网 (nowcoder.com)

使用位运算:

异或可以提供两位的非进位信息

与运算可以提供进位信息

这里的操作是把所有的sum位和进位一起处理了

public int encryptionCalculate(int dataA, int dataB) {
    while (dataB!=0) {
        int c=(dataA&dataB)<<1;//进位
        dataA=dataA^dataB;//本位
        dataB=c;
    }
    return dataA;
}

有一说一看不懂

50. Pow(x, n) - 力扣(LeetCode)

思路:分治,快速幂

还要求空间复杂度o1,我操你妈了

快速幂:当n为偶数,那么xn次方等于x n/2次方 的平方

n为奇数,还得再乘个x

public double myPow(double x, int n) {
    if(x==0.0f)return 0.0d;
    long b=n;
    double res=1.0;
    if(b<0)//负次方的情况
    {
        x=1/x;
        b=-b;
    }
    while(b>0)
    {
        if((b&1)==1)res*=x;//最后一位是1说明让他是奇数,那么res乘一个x
        x*=x;//x执行平方
        b>>=1;//相当于b/2
    }
    return res;//因为你不停除2最后总会留下一个1,所以直接返回res即可
}

数组中只出现一次的两个数字_牛客题霸_牛客网 (nowcoder.com)

有一说一这个也挺难的,就是把他分类

我们知道如果有只出现一次的一个数字,那么对所有的数字异或,会留下这个只出现一次的数字

现在这里有两个只出现一次的a和b,那么我们全部异或,得到的结果就是a和b的异或

因为a和b不同,那么a和b肯定有一位,不同,就是说a的一位为1,b的一位为0

我们找到这一位,然后按这一位是不是为1进行分类,

然后对有相同性质的分别异或,留下来的就是a和b

知识点:x&-x可以取出二进制x中最低位的那个1,这个要牢记啊!!!

public int[] FindNumsAppearOnce (int[] nums) {
    // write code here
    int xorsum=0;
    for(int num:nums)
    {
        xorsum^=num;
    }
    int lsb=(xorsum==Integer.MIN_VALUE?xorsum:xorsum&(-xorsum));//xorsum是-2147483648的时候变为正数会溢出,因为32位的int正数范围是0~2147483647,而为什么是min.value时,直接返回xorsum呢,因为-2147483638二进制是1000000000,最低位的1其实就是她自己
    int t1=0,t2=0;
    for(int num:nums)
    {
        if((lsb&num)!=0)
        {
            t1^=num;
        }else
        {
            t2^=num;
        }
    }
    if(t1>t2)
    {
        return new int[]{t2,t1};
    }
    return new int[]{t1,t2};
}

LCR 138. 有效数字 - 力扣(LeetCode)

这题目太他妈恶心了,老子按照宫水三叶的题解来写

class Solution {
    //思路:就是宫水三叶的
    public boolean validNumber(String s) {
        int n=s.length(),l=0,r=n-1;
        while(l<n&&s.charAt(l)==' ')l++;
        while(r>=0&&s.charAt(r)==' ')r--;
        if(l>r)return false;
        s=s.substring(l, r+1).replace('e', 'E');
        n=s.length();

        int idx=0;
        while(idx<n&&s.charAt(idx)!='E')idx++;//走到有E的地方
        if(idx==n){
            return check(s,true);//说明没E,那么就整个串判断
        }else
        {
            return check(s.substring(0,idx),true)&&check(s.substring(idx+1),false);
        }
    }

    boolean check(String s,boolean isDecimal)
    {
        if(s.equals(".")||s.equals(""))return false;
        int n=s.length();
        for(int i=0,cnt=0;i<n;i++)
        {
            char c=s.charAt(i);
            if(c=='+'||c=='-')
            {
                if(i!=0||i==n-1)return false;//符号没出现在对的地方,返回false
            }else if(c=='.')
            {
                if(!isDecimal)return false;//右半部分只能是整数,如果右半部分有了.说明错了
                if(cnt!=0)return false;//cnt是小数点的个数,如果已经出现过小数点了,那么就错了!
                boolean a=i-1>=0&&Character.isDigit(s.charAt(i-1));
                boolean b=i+1<n&&Character.isDigit(s.charAt(i+1));
                if(!(a||b))return false;//小数点左右至少得有一位是数字
                cnt++;
            }else if(!Character.isDigit(c))return false;//又不是符号又不是数字又不是小数点,直接返回false
        }
        return true;
    }
}

路径总和3

233. 数字 1 的个数 - 力扣(LeetCode)

困难题,恶心的要死啊

反正记住了,那就拿23x4举例子,自己推吧

public int countDigitOne(int n) {
        //cur=0,那么等于高*digit
        //cur=1那么等于高位的加上自己的1在加上地位的数字
        //cur=2,3,....9那么等于高位+1乘digit,因为你这一位本身也可以取1了
        int digit=1;
        int low=0;
        int cur=n%10;//一开始是个位,所以对10取余
        int high=n/10;
        int res=0;
        while(high!=0||cur!=0)
        {
            if(cur==0)res+=high*digit;
            else if(cur==1)res+=high*digit+low+1;
            else res+=(high+1)*digit;
            low+=cur*digit;//将cur加入low
            cur=high%10;//下一轮的cur是本轮high的最低位
            high/=10;
            digit*=10;
        }
        return res;
}

和为S的连续正数序列_牛客题霸_牛客网 (nowcoder.com)

这一题不知道为什么,只能用做成晕的傻逼方法

孩子们的游戏(圆圈中最后剩下的数)_牛客题霸_牛客网 (nowcoder.com)

394. 字符串解码 - 力扣(LeetCode)

31. 下一个排列 - 力扣(LeetCode)

76. 最小覆盖子串 - 力扣(LeetCode)

48. 旋转图像 - 力扣(LeetCode)

437. 路径总和 III - 力扣(LeetCode)

236. 二叉树的最近公共祖先 - 力扣(LeetCode)

5. 最长回文子串 - 力扣(LeetCode)

树的子结构_牛客题霸_牛客网 (nowcoder.com)

二叉搜索树的后序遍历序列_牛客题霸_牛客网 (nowcoder.com)

二叉树的下一个结点_牛客题霸_牛客网 (nowcoder.com)

旋转数组的最小数字_牛客题霸_牛客网 (nowcoder.com)

字符串的排列_牛客题霸_牛客网 (nowcoder.com)


  目录