Day24_数字规律_剑指Offer

剪绳子


medium 原题连接:剪绳子

给你一根长度为 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

示例:

输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36

提示:

  1. 2 <= n <= 58



解题思路


总长度固定,拆成不同长短的子段,算最大乘积

  1. 子段长度越相等,积越大(算术几何均值不等式)
  2. 不要分出长度为1的子段
  3. 自然对数 e 约等于 2.7

所以设总长度为常数N,拆成a段长度为x,我们有:

N = a * x ; ans = x ^ a;

得到:ans = ( x ^ ( 1 / x ) ) ^ N,由于N为常数,ans最终的值会趋近于 2.7 * N,但是绳子要是整数

所以目标是将绳子尽可能化成越多的3

  1. 当长度可以被3整除,全部转为长度为3的绳子,求值
  2. 当长度对3除余,得到2,转换为一个2和其他为3的数段,求值
  3. 当长度对3除余,得到1,转换为一个4和其他为3的数段,求值



Java代码


class Solution {
   public int cuttingRope(int n) {
       if(n <= 3)return n-1;
       int a = (int)n/3, b = n%3;
       if(b == 2) return (int)Math.pow(3,a)*2;
       if(b == 1) return (int)Math.pow(3,a-1)*4;
       return (int)Math.pow(3,a);
  }
}



和为s的连续正数序列


Easy 原题连接: 和为s的连续正数序列

输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。

序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

示例:

输入:target = 9
输出:[[2,3,4],[4,5]]
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]

限制:

  1. 1 <= target <= 10^5


解题思路


连续数组首先想到滑动窗口:

  1. 设立滑动窗口,左端left,右端right,得到窗口总值:sum = left + right
  2. 判断sum与target的关系:
  3. sum == target : 符合目标信息,存储滑动窗口中的数据,窗口小数端移动(符合题目要求:不同序列按照首数字大小排列)
  4. sum < target :滑动窗口大数端移动
  5. sum > target :滑动窗口小数端移动
  6. 循环2,直至left与right相遇:(窗口最小数已经大于target的一半,无法划分了)
// 当你需要从0开始赋值数组,但是你的值随另一个数组变动:
for(int i=left; i<=right; i++) {
ans[i-left] = i;
}



Java代码


class Solution {
   public int[][] findContinuousSequence(int target) {
       int left = 1, right =2, sum = left + right;
       List<int[]> ansList = new ArrayList<>();
       while(left < right) {
           if(sum == target) {
               int[] ans = new int[right - left + 1];
               for(int i=left; i<=right; i++) {
                   ans[i-left] = i;
              }
               ansList.add(ans);
          }
           if(sum >= target) {
               sum -= left;
               left++;
          }else {
               right++;
               sum += right;
          }
      }
       return ansList.toArray(new int[0][]);
  }
}



圆圈中最后剩下的数字


Easy 原题连接:圆圈中最后剩下的数字

0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。

例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

示例:

输入: n = 5, m = 3
输出: 3
输入: n = 10, m = 17
输出: 2

提示:

  1. 1 <= n <= 10^5
  2. 1 <= m <= 10^6



解题思路


约瑟夫环问题:每次都会删除环中一个节点,想知道谁留到最后,由题目提示给的数据量来看,死算是过不了的

首先,在最后一次删除后,所剩下的一个数,是当前数组的0位(因为只有一位了)

每次删除后,从下一个开始当作新的删除计数,删除 当前值+( m % i ), i 为当前循环中的数的总数,为了避免总数超出上线,对 i 去余

综合以上两者,可以从一位向前推到(已知最后剩下的是最后数组的0号位,能退出前一次删除的是哪个位置)

直到数组长度回复到n,返回最初0号位目前所在的位置即可



Java代码


class Solution {
   public int lastRemaining(int n, int m) {
       if(n == 1) return 0;
       int ans = 0;
       for(int i=1; i<=n; i++) {
           ans = (ans + m) % i;
      }
       return ans;
  }
}


我的博客:Day24_数字规律_剑指Offer | IT蛋的个人博客 (xcscx.github.io)

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
IT蛋
下载 APP