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
提示:
2 <= n <= 58
解题思路
总长度固定,拆成不同长短的子段,算最大乘积
- 子段长度越相等,积越大(算术几何均值不等式)
- 不要分出长度为1的子段
- 自然对数 e 约等于 2.7
所以设总长度为常数N,拆成a段长度为x,我们有:
N = a * x ; ans = x ^ a;
得到:ans = ( x ^ ( 1 / x ) ) ^ N,由于N为常数,ans最终的值会趋近于 2.7 * N,但是绳子要是整数
所以目标是将绳子尽可能化成越多的3
- 当长度可以被3整除,全部转为长度为3的绳子,求值
- 当长度对3除余,得到2,转换为一个2和其他为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 <= target <= 10^5
解题思路
连续数组首先想到滑动窗口:
- 设立滑动窗口,左端left,右端right,得到窗口总值:sum = left + right
- 判断sum与target的关系:
- sum == target : 符合目标信息,存储滑动窗口中的数据,窗口小数端移动(符合题目要求:不同序列按照首数字大小排列)
- sum < target :滑动窗口大数端移动
- sum > target :滑动窗口小数端移动
- 循环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 <= n <= 10^5
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;
}
}