day24

1.剑指 Offer 14- I. 剪绳子

2=1+1,3=1+2,

4 = 2 + 2,5 = 3 + 2,6 = 3 + 3,7 = 3 + 4,8 = 3 + 5 = 3 + 3 + 2,9 = 5 + 4 = 3 + 2 + 4. . . . . .

可以发现,其实从4开始,每个数字都可以由2和3组成,尽可能的多分出一些3乘积就会大些

举个栗子:8 = 3 + 5,当3和5(3 + 2)各自的乘积取最大值,两者再相乘那么8就会取得乘积的最大值。同样的每个数字都可以这样拆分,每个拆分出来的数分别取得乘积的最大值,把这些最大值相乘就得到我们要求的(有种动态规划的感觉,就是这个数的最大乘积取决于 前面组成它的数 的最大乘积)

2和3要单独处理,因为它们不得不 要拆分出一个1来,while(n - 3 > 1) ,这个条件是,如果最后剩下的n不大于4,就直接相乘。为什么如果最后是4要直接退出循环乘4呢,因为最后4继续减3处理的话4会被拆分成4 = 3 +1;但是中间不能直接减去一个4然后乘4,只有最后只剩下4的时候才可以(5 = 3 + 2,5 = 4 + 1;6 = 3 + 3,6 = 4 + 2,都是前者更大)

 1 class Solution {
 2 public:
 3     int cuttingRope(int n) {
 4       if(n <= 3) return n - 1;
 5       int res = 1;
 6       while(n - 3 > 1){ //一直减3,减一个3就乘一个3
 7          res *= 3;
 8          n -= 3;
 9       }
10       res = res * n;
11       return res;
12     }
13 };

 

2.剑指 Offer 57 - II. 和为 s 的连续正数序列

 看到连续,就想到双指针

 1 class Solution {
 2 public:
 3     vector<vector<int>> findContinuousSequence(int target) {
 4       vector<vector<int> > res;
 5       int i = 1,j = 2,s = 3;
 6       while(i < j){
 7           if(s == target){
 8               vector<int> ans;
 9               for(int k = i;k <= j;k ++)
10                ans.push_back(k);
11               res.push_back(ans);
12           }
13           if(s < target){ //注意if和else里两条语句的顺序
14            j ++; 
15            s += j;
16           }
17           else{
18             s -= i;
19              i ++;
20           }
21       }
22           return res;
23       }
24 };

 

3.剑指 Offer 62. 圆圈中最后剩下的数字

 约瑟夫环问题

 1)暴力解法(会超时,不建议)

 1 class Solution {
 2 public:
 3     int flag[100001];
 4     int lastRemaining(int n, int m) {
 5         if(n == 1)  return 0;
 6         int cnt1 = n - 1,cnt2 = 0;
 7         while(cnt1){
 8           for(int i = 0;i < n;i ++){
 9               if(flag[i] == 0){
10                 cnt2 ++;
11                 if(cnt2 == m){
12                     flag[i] = 1;
13                     cnt2 = 0;
14                     cnt1 --;
15                     if(cnt1 == 0) break;
16                 }
17               }
18           }
19         }
20         for(int i = 0;i < n;i ++)
21          if(flag[i] == 0)
22           return i;
23         return 0;
24     }
25 };

 2)问题用f(n,m)表示 ,表示n个数时,数到m时删除那个数后剩下的最终的编号(位置序列)(不是指具体某个数,而是一排数!!!)

      结合下面两篇题解理解

  假设n = 11,m = 3,有 0,1,2,3,4,5,6,7,8,9 一共10个数字

 约瑟夫环问题的三种解法讲解 - 力扣(LeetCode)

 

  

  f(1,3)是最后留下来的数的位置,也就是我们要求的。我们一步步的回退,找到这个数在最原始的一排数里的位置,比如这个例子:第一次回退找到这个数在f(2,3)时的位置:1,再回退,找到它在f(3,3)时的位置:1,再回退,找到它在f(4,3)时的位置:0,最后一次回退,找到它在f(5,3)时的位置:3,在最原始一排数(0,1,2,3,4)中,底数3对应的数是3

 

1 class Solution {
2 public:
3     int lastRemaining(int n, int m) {
4        if(n == 0)  return 0;
5        return (lastRemaining(n - 1,m) + m) % n;
6     }
7 };

 也可直接从0开始递推

 1 class Solution {
 2 public:
 3     int lastRemaining(int n, int m) {
 4         int x = 0;
 5         for (int i = 2; i <= n; i++) {
 6             x = (x + m) % i;
 7         }
 8         return x;
 9     }
10 };

 注:我们求出的是数在数组中对应的位置,也就是说,如果位置上 对应的数 和位置数不同,我们要输出位置上的那个数,而不是输出位置数。比如我们刚刚上面那个例子(0,1,2,3,4),位置3对应的数字是3,我们就输出3,如果给出的数组是(6,3,8,9,7),位置3对应的是9,我们应该输出9

posted @ 2022-07-20 11:49  balabalahhh  阅读(30)  评论(0)    收藏  举报