思路一:贪心算法

推论一: 将绳子 以相等的长度等分为多段 ,得到的乘积最大。

推论二: 尽可能将绳子以长度 33 等分为多段时,乘积最大。

核心思路是:尽可能把绳子分成 长度为3的小段,这样乘积最大。

步骤如下:

(1)如果 n === 4,返回4
(2)如果 n > 4,分成尽可能多的长度为3的小段,每次循环长度n减去3,乘积res乘以3;最后返回时乘以小于等于4的最后一小段

class Solution {
public:int cuttingRope(int n) {//1、任何大于1的数都可由2和3相加组成(根据奇偶证明)//2、因为2*2=1*4,2*3>1*5, 所以将数字拆成2和3,能得到的积最大//3、因为2*2*2<3*3, 所以3越多积越大 时间复杂度O(n/3),用幂函数可以达到O(log(n/3))if(n==1 || n==2) return 1;  //1*1if(n==3) return 2;  //1*2if(n==4) return 4;  //2*2 || 1*4int sum=1;while(n>4)   //当n=4时可以分为2+2,也可以不分割;   当n>4时,即n=5起可拆分为3、2的和{sum *= 3;n -= 3;}return sum*n;}
};

贪心优化:由于正常的贪心算法是不断对数进行 n - 3 然后 result × 3,如果这个 n 很大,那么重复减 3 的次数会很多,所以考虑对这个地方进行优化,直接 n / 3 代替不断 n -= 3

思路
先获得 n 的余数 yuShu = n % 3 = 0、1、2,然后获得幂的次数 pow = n / 3

考虑在余数是 1 时,要对 / 3 后的结果回溯一次,即 pow 要 - 1,然后直接乘 4 就行

为了简便运算,将余数是 1 和 0 合并起来,在 / 3 后都进行一次 -1,即回溯一次,然后

result = 3 ^(pow-1) * (yuShu + 3)  即可

yuShu = 1 时,乘 4

yuShu = 0 时,乘 3

切分规则:
(1)最优: 3。把绳子尽可能切为多个长度为 3的片段,留下的最后一段绳子的长度可能为 0,1,2  三种情况。
(2)次优: 2 。若最后一段绳子长度为 2;则保留,不再拆为 1+1 。
(3)最差: 1 。若最后一段绳子长度为 1;则应把一份 3 +1 替换为 2 + 2,因为 2 × 2 > 3 × 1。

算法流程:
(1)当 n≤3 时,按照规则应不切分,但由于题目要求必须剪成 m>1 段,因此必须剪出一段长度为 1 的绳子,即返回 n - 1。
(2)当 n>3 时,求 n 除以 3 的 整数部分 a 和 余数部分 b(即 n = 3a + b ),并分为以下三种情况:

当 b = 0时,直接返回 3^a;
         当 b = 1时,要将一个 1 + 3转换为 2+2,因此返回 3^{a-1}  ×4;
         当 b = 2时,返回 3^a ×2。

class Solution {
public:int cuttingRope(int n) {if(n==1 || n==2) return 1;if(n==3) return 2;if(n==4) return 4;int yuShu = n % 3;  //余数// int mi = n / 3;     //幂的次数if(yuShu==0){return (int)pow(3,n/3);}if(yuShu==1){return (int)pow(3,n/3-1)*(yuShu+3);}if(yuShu==2){return (int)pow(3,n/3)*yuShu;}return 0;}
};

思路二:动态规划 

思路:对于的长度为n的绳子,当 n ≥ 2 时,可以剪成至少两个绳子。令 k 是剪出的第一段绳子,则剩下的部分是 n−k,n−k 可以不继续剪,或者继续剪成至少两段绳子(一个问题可以分解为相似的子问题因此想到动态规划)。由于每个绳子长度对应的最大乘积取决于比它小的绳子对应的最大乘积,因此可以使用动态规划求解。

算法

(1)确定dp数组以及下标的含义                                                                                               

dp[i] 表示将长度为 i 的绳子剪成至少两段绳子之后,这些绳子长度的最大乘积

(2)确定状态转移方程

当 i ≥ 2 时,假设对长度为 i 绳子剪出的第一段绳子长度是 j(1≤j<i),则有以下两种方案:

(1)将 i 剪成 j 和 i-j 长度的绳子,且 i−j 不再继续剪,此时的乘积是 j×(i−j) ;

(2)将 i 剪成 j 和 i−j 长度的绳子,且 i−j 继续剪成多段长度的绳子,此时的乘积是 j×dp[i−j]

因此,当 j 固定时,有 dp[i] = max(j×(i−j),j×dp[i−j])。由于 j 的取值范围是 1 到 i/2 ,需要遍历所有的 j 得到最大的 dp[i]

(3)初始化状态

0 不是正整数,1 是最小的正整数,0 和 1 都不能拆分,因此 dp[1]=1,dp[2]=2,dp[3]=3。

(4)遍历顺序

由状态转移方程知道dp[i] 是从 j×(i−j)和j×dp[i−j] 且j 的取值范围是 1 到 i/2 ,需要遍历所有的 j 得到dp[i]所以从前往后遍历。
(5)返回值

最终得到dp[n]的值即为将长度为n的绳子拆分成至少两段绳子之后,这些绳子长度的最大乘积。

class Solution {
public:int cuttingRope(int n) {//int* dp = new int[n+1];vector<int> dp(n+1);if(n==1 || n==2) return 1;if(n==3) return 2;dp[1] = 1; dp[2] = 2; dp[3] = 3;for(int i = 4;i <= n;i++){//j<=i/2是因为1*3和3*1是一样的,没必要计算在内,只要计算到1*3和2*2就好了// max(j*(i-j),j*dp[i-j]) 中 j*(i-j)指的是分割一次后的乘积;j*dp[i-j]指分割一次后,// 剩余部分继续分割后的最大乘积,前面已经求解过,所以只需要取结果// 下面综合起来就是,但j取不同时,与前一次j取值后的dp[i]比较,取最大值,直到j遍历完for(int j = 1;j <= i/2;j++){dp[i] = max(dp[i],max(j*(i-j),j*dp[i-j]));// dp[i] = max(dp[i],dp[j]*dp[i-j]);//max(j*(i-j),j*dp[i-j]是由于减去第一段长度为j的绳子后,可以继续剪也可以不剪//max(dp[i],Math.max(j*(i-j),j*dp[i-j]))是当j不同时,求出最大的dp[i]}}return dp[n];}
};

剑指offer面试题14-I:剪绳子相关推荐

  1. 剑指offer——面试题14:调整数组顺序使奇数位于偶数前面

    剑指offer--面试题14:调整数组顺序使奇数位于偶数前面 Solution1: 顺序交换,比较好的算法!!! class Solution { public:void reOrderArray(v ...

  2. 剑指offer面试题[14]-调整数组顺序使奇数位于偶数前面

    题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 分析: 这个题目的最 ...

  3. 剑指offer 面试题三 找出数组中重复的数字

    1 import org.junit.Test; 2 3 import java.util.Arrays; 4 import java.util.HashSet; 5 6 public class D ...

  4. 剑指offer——面试题44:扑克牌顺子

    剑指offer--面试题44:扑克牌顺子 Solution1: 20180907重做 书上的思路. class Solution { public:bool IsContinuous(vector&l ...

  5. 【剑指Offer面试题】 九度OJ1510:替换空格

    c/c++ 中的字符串以"\0"作为结尾符.这样每一个字符串都有一个额外字符的开销. 以下代码将造成内存越界. char str[10]; strcpy(str, "01 ...

  6. [剑指offer]面试题第[68-2]题[Leetcode][第236题][JAVA][二叉搜索树的最近公共祖先][递归]

    [问题描述][中等] 235/68-1 搜索二叉树 236/68-2 二叉树 [解答思路] 递归 时间复杂度:O(N) 空间复杂度:O(N) 情况 1. , 2. , 3. , 4. 的展开写法如下. ...

  7. [剑指offer]面试题第[57]题[Leetcode][第167题][JAVA][和为s的两个数字][两数之和][HashSet][二分][双指针]

    [剑指offer]面试题第[57]题[Leetcode][第167题][第1题] 有序无序之分 题目输出不同之分 以下解法按照[剑指offer]面试题第[57]题进行题解 [问题描述][简单] 输入一 ...

  8. 两个数组中对应的下标的值合成一个新的数组_剑指 offer 面试题精选图解 03 . 数组中重复的数字

    今天分享的题目来源于 LeetCode 上的剑指 Offer 系列 面试题03. 数组中重复的数字. 题目链接:https://leetcode-cn.com/problems/shu-zu-zhon ...

  9. 剑指offer面试题[64]-数据流中的中位数

    题目描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值. 分 ...

最新文章

  1. document.getElementByName()的用法
  2. 与陆毅擦肩而过。。。
  3. 记录 Duplicate spring bean id dubbo
  4. 【Java】封装带有泛型的序列化文件工具类
  5. jquery 读取页面load get post ajax 四种方式代码写法
  6. c语言给一个函数添加功能,【C语言】请编写实现以下功能函数:实现对一个8bit数据(unsigned char)的指定位(例如第8位)的置0或置1操作,并保持其他位不变...
  7. 盘点七大类当前世界流行的数据挖掘技术
  8. 关于[知识竞赛现场管理系统-双屏PPT版]内置的第三方答题平台以及[评委计分系统-双屏专业版]的特殊疑难问题 汇编
  9. Banner设计文字如何排版,如何设计字体
  10. 【问】存货盘点单中的数量在盘点报表和盘点差异处理中看不到
  11. 不用电脑怎么设置路由器
  12. 芯片工程师成长之路_从入门到精通,电子硬件工程师的成长之路
  13. nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
  14. 饿了么推荐系统的从0到1
  15. Ty-JDBC学习笔记
  16. html和ui关系,ue和ui的区别是什么
  17. 前端经典面经--助你金九银十面试无烦恼
  18. 视频拼接 python_LeetCode-python 1024.视频拼接
  19. 【新能源】从“材料”到“电池组”一文读懂动力电池生产全流程!
  20. 2020丘成桐科学奖计算机名单,2016东润丘成桐科学奖(数学)国内各赛区获奖名单...

热门文章

  1. MTK android系统修改屏幕密度
  2. 天气转凉除了衣服要多穿,知识也要多多积累啊 Java——TreeMap常用methods,还不赶紧收藏起来
  3. uniapp 发行 原生APP本地打包 安卓APK(最全的步骤)
  4. uniapp 阿里图库图标引用
  5. 计算机二级Office应用之Excel中的函数(2)
  6. MyBatis之缓存机制
  7. windows python2和python3共存_windows python2与python3环境共存简易方法
  8. Java修炼之凡界篇 筑基期 第01卷 入门 番外3 认识IDE和IDEA
  9. Gradle 安装配置详解
  10. 安装双系统遇到的问题:0xc000000e和0xc000000f