20-今日三扣(剑指Offer)-变态青蛙跳台阶(dp)-矩形覆盖(dp)-二进制1的个数(移位).md

题目描述

牛客网

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

思路:

无论怎么跳,对于n级台阶,青蛙最后一跳可能是1~n。假设青蛙对于m级阶梯的跳法有f(m)种。

  • 最后一跳是1,前面需要跳n-1级,所以此时为f(n-1)种可能。
  • 最后一条是2, 前面需要跳n-2级,此时为f(n-2)种可能。
  • 最后一条是n,则青蛙一跃而上,此时只有1种跳法

故最终为f(n-1)+f(n-2)+…f(1)+1

使用动态规划,自底向上的构建思路,先计算f(1), f(2)…存储到dp数组中。

题解:

public class Solution {
    public int JumpFloorII(int target) {
        if(target == 0){
            return 0 ;
        }
        if(target ==1){
            return 1;
        }
        int[] dp = new int[target+1];
        dp[0] = 0;
        dp[1] = 1;
        
        for(int i = 2; i <= target; i++){
            dp[i] = 1;
            for(int j = 1; j<i; j++){
                dp[i] += dp[j];
            }
        }
        return dp[target];
    }
}

题目描述

牛客网

我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

比如n=3时,2*3的矩形块有3种覆盖方法:

题解:

这个和变态的小青蛙跳台阶差不多,甚至更简单

仍然考虑n时,最后一块的放置有两种方案:

  • 竖着放一块,此时之前的长度为n-1,也就是这时应该有f(n-1)种方案。
  • 横着放两块,此时之前的长度为n-2(因为瓷砖横着的长度是2),这种情况下有f(n-2)中方案。

那么对于n的解决方案数:
f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n) = f(n-1)+f(n-2) f(n)=f(n1)+f(n2)

可以从底向上,也可以使用递归从上向下写。

public class Solution {
    public int RectCover(int target) {
        if(target==1){
            return 1;
        }
        if(target == 0){
            return 0;
        }
        int dp[] = new int[target+1];
        dp[0] = 1;
        dp[1] = 1;
        for(int i=2; i<=target; i++){
            dp[i] = dp[i-1]+dp[i-2];
        }
        return dp[target];
    }
}

空间优化:

public class Solution {
    public int RectCover(int target) {
        if(target==1){
            return 1;
        }
        if(target == 0){
            return 0;
        }
        
        int ppre = 1;
        int pre = 1;
        int cur=0;
        for(int i=2; i<=target; i++){
            cur = pre+ppre;
            ppre = pre;
            pre = cur;
        }
        return cur;
    }
}

题目描述

输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。

牛客网

题解(参考牛客官方)

使用除2取模,在100000000…0,31个0时会出现问题。输出为0,我们希望输出为1.

有符号整数在计算机中以补码的形式存储的。对于正数,我们无需考虑,直接进行移位比较就好,对于负数,我们在右移的时候,左侧会自动补1。这会影响我们的判断。

所以我们的解决方案是移动mark而不是移动原数。

public class Solution {
    public int NumberOf1(int n) {
        int mark = 1;
        int ans = 0;
        while(mark!=0){
            if((mark & n)!=0){
                ans++;
            }
            mark = mark<<1;
        }
        return ans;
    }
}
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页