LeetCode力扣(剑指offer 11-15)11.旋转数组的最小数字,12. 矩阵中的路径,13. 机器人的运动范围,14. 剪绳子,14- II. 剪绳子 II,15. 二进制中1的个数

剑指 Offer 11. 旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。

给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为 1。  

注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。

n == numbers.length
1 <= n <= 5000
-5000 <= numbers[i] <= 5000
numbers 原来是一个升序排序的数组,并进行了 1 至 n 次旋转

题解:

原数组是一个升序的数组,并进行了 1 至 n 次旋转。意味着除了n次旋转,旋转后的数组必然存在两个升序的子数组,且右边的子数组是“小”的那部分,也是我们最终要定位的数组,最小值必然在里面。

 如上图所示,我们先设置两个指针指向数组首尾,采用二分查找,计算出两个点的中点,我们需要知道中点是在第一个子数组还是第二个子数组里。

如果在第一个中,那么中点元素大于等于p1所指的元素,将p1移到中点的位置,如图a。

如果在第二个中,那么中点元素小于等于p2所指的元素,将p2移到中点的位置,如图b。

当处于图c的情况后,说明已经找到最小值了。

注意!注意!注意!

1.上面所讲的情况只不包含1,2,3,4,5这种无逆转数组或者叫n次逆转数组。

2.不包含以下的情况

 所以需要特别处理,情况1的处理方式是,得出的结果和数组第一个数再进行比较。

情况2的处理方式是,加入判断,当怕p1,p2,mid三个索引指向的数都相等时,用遍历的方法查找最小值。

代码:

class Solution {
public:
    int minArray(vector<int>& numbers) {
        int index1=0,indexMid=0,index2=numbers.size()-1;

        while(index1<index2){
            if(index2-index1<=1)        //已经找到最小值,跳出循环
                break;

            indexMid=(index1+index2)/2;
            //特殊情况,1,0,1,1,1,这种情况下只能循环判断了
            if(numbers[indexMid]==numbers[index1] && numbers[indexMid]==numbers[index2]){
                for(int i=index1+1;i<=index2;++i)
                    if(numbers[index2]>numbers[i]) 
                        index2=i;  
                break;
            }
            if(numbers[indexMid]>=numbers[index1]) index1=indexMid;
            else if(numbers[indexMid]<=numbers[index2]) index2=indexMid;
        }

        return min(numbers[index2],numbers[0]); //防止n次旋转,如1,3,5
    }
};

结果:

剑指 Offer 12. 矩阵中的路径

 

题解:

首先,遍历矩阵,如果遇到与字符串第一个字符相同的元素,就开始递归。

递归,选择pos==word.size()作为终止条件,走到这一步返回true

然后,设置边界,防止越界溢出。

注意,如果board[i][j]这个点走过,就把它置为*,防止形成回路又走到自己了。在下一次递归完成之后恢复原来的数值。

代码:

class Solution {
public:
    bool dfs(vector<vector<char>>& board, string word,int i,int j,int pos){
        if(pos==word.size())
            return true;
        
        if(i<0||j<0||i>=board.size()||j>=board[0].size()||board[i][j]!=word[pos])
            return false;
        char c=board[i][j];//防止又找到自己
        board[i][j]='*';
        bool res=dfs(board,word,i+1,j,pos+1)||dfs(board,word,i,j+1,pos+1)||dfs(board,word,i-1,j,pos+1)||dfs(board,word,i,j-1,pos+1);
        board[i][j]=c;
        return res;
    }

    bool exist(vector<vector<char>>& board, string word) {
        for(int i=0;i<board.size();++i)
            for(int j=0;j<board[0].size();++j)
                if(dfs(board,word,i,j,0))
                    return true;
        return false;
    }
};

结果:

剑指 Offer 13. 机器人的运动范围

题解:

方法一:递归

思想和题12一样,只不过缺了一个矩阵,所以需要自己构建一个。范围是0~100,所以用i%10+i/10+j%10+j/10判断即可

首先,从(0,0)开始递归,设置终止条件,越界,已走过的节点,数位之和小于k三者作为终止条件。

然后,把当前节点设为true,res值+1,开始从上,下,左,右继续递归。

代码:

class Solution {
public:
    void dfs(vector<vector<bool>>&dp,int i, int j, int k,int &res){
        if(i<0||j<0||i>=dp.size()||j>=dp[0].size()||dp[i][j]==true||i%10+i/10+j%10+j/10>k)
            return;
        ++res;
        dp[i][j]=true;
        dfs(dp,i-1, j, k,res);
        dfs(dp,i+1, j, k,res);
        dfs(dp,i, j-1, k,res);
        dfs(dp,i, j+1, k,res);
    }

    int movingCount(int m, int n, int k) {
        vector<vector<bool>>dp(m, vector<bool>(n, false));
        int res=0;
        dfs(dp,0,0,k,res);
        return res;
    }
};

结果:

方法二:动态规划

我们只需要判断当前位置的上面的点和左边的点有没有走过,再判断当前的点的数位的和是否小于k即可。

代码:

class Solution {
public:
    int sum(int num1,int num2){
        int sum=0;
        while(num1||num2){
            sum+=num1%10+num2%10;
            num1=num1/10;
            num2=num2/10;
        }
        return sum;
    }
    int movingCount(int m, int n, int k) {
        vector<vector<bool>>dp(m+1, vector<bool>(n+1, false));
        dp[0][1]=true;
        int res;
        for(int i=0;i<m;++i)
            for(int j=0;j<n;++j)
                if((dp[i][j+1]||dp[i+1][j])&&sum(i,j)<=k){
                    dp[i+1][j+1]=true;
                    ++res;
                }
        return res;
    }
};

结果:

剑指 Offer 14- I. 剪绳子

题解:

方法一:3的个数

尽量多找3,因为像5,2*3最大;6,3*3最大;8,3*3*2最大

如果是4的话,让它变成2*2,不是1*3,也就是说,n>4才起步计算

首先,排除2,3的情况,如果大于4则进行循环找3的工作

最后剩下的,必然小于4,这时候就不需要再拆分了,直接做乘法操作即可

代码:

class Solution {
public:
    int cuttingRope(int n) {
        if(n==2)return 1;
        if(n==3)return 2;
        int res=1;
        while(n>4){
            n=n-3;
            res*=3;
        }
        return res*n; 
    }
};

结果:

方法二:

首先,排除特殊情况,n=2或者3的时候。

从4到n开始遍历,

代码:

class Solution {
public:
    int cuttingRope(int n) {
        if(n<4) return n-1;
        vector<int>dp(n+1,0);
        dp[1]=1;dp[2]=2;dp[3]=3;
        for(int i=4;i<=n;++i)
            for(int j=1;j<=i/2;++j)
                dp[i]=max(dp[j]*dp[i-j],dp[i]);
    
        return dp[n];
    }
};

结果:

剑指 Offer 14- II. 剪绳子 II

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m - 1] 。请问 k[0]*k[1]*...*k[m - 1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

题解:

和上一题一模一样,只是增加n的长度,结果需要取模.

考虑到n 的最大长度会达到1000,用动态规划的话需要建立n+1个数组,空间复杂度会很高。而且不容易判断大小,所以采用上题的方法一

代码:

class Solution {
public:
    int cuttingRope(int n) {
        if(n < 4){
            return n - 1;
        }
        long res = 1;
        while(n > 4){
            res  = res * 3 % 1000000007;
            n -= 3;
        }
        return (int) (res * n % 1000000007);
    }
};

结果:

题解:

代码:

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int res=0;
        while(n){
            ++res;
            n=n&n-1;
        }
        return res;
    }
};

结果:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木白CPP

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值