剑指 Offer 14- I. 剪绳子
数学
根据求导等数学公式可以得出,最好的情况是每一段相等其次是3的元素尽可能多。
class Solution {public:int cuttingRope(int n) {if(n <= 3) return n-1;int a = n / 3, b = n % 3;if(b == 0) return pow(3, a);if(b == 1) return pow(3, a-1)*4;return pow(3, a)*2;}};
动态规划的写法
- 根据子集求更大集,找到子集与父集之间的规律。
 这里的dp[1], dp[2], dp[3]代表的是基本单元的意思,并不是长度为3的情况下最大值。
class Solution {public:int cuttingRope(int n) {if( n <= 3)return n-1;vector<int> dp(n + 1);dp[1] = 1, dp[2] = 2, dp[3] = 3;for(int len = 4; len <= n; len++){for(int k = 1; k < len; k++){dp[len] = max(dp[len], dp[k] * dp[len - k]);}}return dp[n];}};
剑指 Offer 14- II. 剪绳子 II
本题与之前的剪绳子1大致相同,唯一不同就是要考虑大数越界情况下的求余问题。
这一题不能够再使用dp求解,因为数值过大,需要取模。但是dp算法需要枚举多个值选最大的,而取模之后的大小不能反映真实的大小,以至于的不到正确的答案。
- djp的时间复杂度为n方,本题的数据范围是1000以内不会超时,如果数据范围再次扩大肯定会超时
 
public class Solution {public int CuttingRope(int n) {//处理特殊情况if(n==2) return 1;if(n==3) return 2;if(n==4) return 4;long ans = 1;int mod = 1000000007;//当大于4的时候,先分出一段长度为3的,直到长度小于等于4,则不再分while(n>4){ans=ans*3%mod;n-=3;}return (int)(ans*n%mod);}}
计算过程中爆int
这里出现了一个问题,有下面这样一个等式
int mypow(long base, int consult, long mod) {int ret = 1; // 返回值定义成 long 类型,防止溢出for (int i = 0; i < consult; i++) {ret = (ret * base) % 1000000007;}return ret;}
其中看起来好像不会溢出,但是实际上确溢出了。我的猜测是计算过程中,就是不到取模那一步就会溢出,因为进行乘法运算时,运算结果会中间转存到一个int类型的空间。此时超出范围则溢出。
long long mypow(long base, int consult, long mod) {long long ret = 1; // 返回值定义成 long 类型,防止溢出for (int i = 0; i < consult; i++) {ret = (ret * base) % 1000000007;}return ret;}
剑指 Offer 43. 1~n 整数中 1 出现的次数
- 这里 注意0LL代表longlong类型的0,主要是为了匹配max函数;
 - 先计算出每个位置上有多少1,然后把剩下来的部分单独计算。
 - 比如每个百分位,对于数字来说都会出现 n/1000 * 100个1,然后计算剩下的部分
 剩下的部分<100则百分位出现1的次数是0, 如果在100到200之间就是 n%1000 - 100+1,如果大于200则固定为100;
class Solution {public:int countDigitOne(int n) {// mulk 表示 10^k// 在下面的代码中,可以发现 k 并没有被直接使用到(都是使用 10^k)// 但为了让代码看起来更加直观,这里保留了 klong long mulk = 1;int ans = 0;for (int k = 0; n >= mulk; ++k) {ans += (n / (mulk * 10)) * mulk + min(max(n % (mulk * 10) - mulk + 1, 0LL), mulk);mulk *= 10;}return ans;}};
剑指 Offer 44. 数字序列中某一位的数字
```shell class Solution { public: int findNthDigit(int n) {
int section_cnt = 9; //当前数长下,有多少个这样长的数int num_len = 1; //每个数的长度while ((long)section_cnt * num_len < n){n -= section_cnt * num_len;section_cnt *= 10;num_len ++;}section_cnt /= 9; //比如是1000int target_num = section_cnt + (n - 1) / num_len; //比如1004int idx = (n - 1) % num_len; //比如1004return to_string(target_num)[idx] - '0';
} };
```
