LeetCode心得体会

刷题心得体会

自己在刷题的时候,总结出的一些适用于自己的小心得体会。

  1. 空间换时间
    要求时间复杂度为O(N)时,一个很普遍的思路是使用HashMap或HashSet来进行存储,利用哈希表的特性来进行存储。
  2. 前缀和
    对于求区间和的问题,我们很容易想到利用前缀和数组来优化其查询速度

    前缀和wiki:https://oi-wiki.org/basic/prefix-sum/

  3. 双指针
    • 快慢指针

    • 左右指针
      4.回溯法

LinkedList result = new LinkedList();
public void backtrack(路径,选择列表){
    if(满足结束条件){
        result.add(结果);
    }
    for(选择:选择列表){
        做出选择;
        backtrack(路径,选择列表);
        撤销选择;
    }
}
  1. 快速幂

    快速幂是一种简单而有效的小算法,它可以以[公式]的时间复杂度计算乘方。快速幂不仅本身非常常见,而且后续很多算法也都会用到快速幂。
    无非是一个二分的思路。我们很自然地可以得到一个递归方程

  • 非递归快速幂
    在这里插入图片描述
//递归快速幂
int qpow(int a, int n)
{
   if (n == 0)
       return 1;
   else if (n % 2 == 1)
       return qpow(a, n - 1) * a;
   else
   {
       int temp = qpow(a, n / 2);
       return temp * temp;
   }
}
  • 递归快速幂
    我们换一个角度来引入非递归的快速幂。还是7的10次方,但这次,我们把10写成二进制的形式,也就是 [公式] 。

现在我们要计算 7^(1010)2 ,可以怎么做?我们很自然地想到可以把它拆分为 7^(1000)2*7^(10)2 . 实际上,对于任意的整数,我们都可以把它拆成若干个 [公式] 的形式相乘。而这些[公式],恰好就是 7^17^27^4……我们只需不断把底数平方就可以算出它们。

	//非递归快速幂
int qpow(int a, int n){
    int ans = 1;
    while(n){
        if(n&1)        //如果n的当前末位为1
            ans *= a;  //ans乘上当前的a
        a *= a;        //a自乘
        n >>= 1;       //n往右移一位
    }
    return ans;
}

最初ans为1,然后我们一位一位算:

1010的最后一位是0,所以a^1 这一位不要。然后1010变为101,a变为a^2

101的最后一位是1,所以a^2这一位是需要的,乘入ans。101变为10,a再自乘。

10的最后一位是0,跳过,右移,自乘。

然后1的最后一位是1,ans再乘上a^8。循环结束,返回结果。
在这里插入图片描述
这里的位运算符,>>是右移,表示把二进制数往右移一位,相当于/2;&是按位与,&1可以理解为取出二进制数的最后一位,相当于%2==1。这么一等价,是不是看出了递归和非递归的快速幂的关系了?虽然非递归快速幂因为牵扯到二进制理解起来稍微复杂一点,但基本思路其实和递归快速幂没有太大的出入。

节选自快速幂专栏:https://zhuanlan.zhihu.com/p/95902286,原文写的非常优秀!
50. Pow(x, n)

  1. 128. 最长连续序列
    523. 连续的子数组和
    560. 和为K的子数组
    974. 和可被 K 整除的子数组
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章