当前位置: 首页 > wzjs >正文

c网站开发教程天津百度seo

c网站开发教程,天津百度seo,如何创办公司,文字logo免费设计在线生成动态规划的核心思想 -- 以空间换时间 复杂点说通过分解问题为子问题并存储子问题解来优化复杂计算的算法策略。 简单看个问题。 一,初始:求最长连续递增子序列 nums [10,9,2,5,3,7,101,18] 求上面数组中的最长连续递增子序列,输出其长度 …

动态规划的核心思想 -- 以空间换时间

复杂点说通过分解问题为子问题并存储子问题解来优化复杂计算的算法策略。

简单看个问题。

一,初始:求最长连续递增子序列

nums = [10,9,2,5,3,7,101,18]

求上面数组中的最长连续递增子序列,输出其长度

暴力解法中我们需要以每个数为开头去遍历数组,得到最长的子数组。

会产生如下遍历

3,7,101

7,101

可以看到,有重复的计算。我们先用java写一下暴力解法。

暴力解法
    public int lengthOfLIS(int[] nums) {if (nums == null || nums.length == 0) {return 0;}int res = 0;for (int i = 0; i < nums.length; i++) {int temp = 1; // 当前子序列的长度,初始为1(单个元素)for (int j = i + 1; j < nums.length; j++) {if (nums[j] > nums[j - 1]) {temp++;} else {break;}}res = Math.max(res, temp); // 更新最长子序列的长度}return res;}

双重for循环,时间复杂度为 (O(n^2)),空间复杂度为 (O(1))。

动态规划

初始化dp的int数组。值为到当前位置的最大连续数。这样整个遍历完dp数组的值应该是

[1,1,1,2,1,2,3,1]。 可以看到最大长度为3。

    /*** 方法二: 动态规划求解连续递增子序列* @param nums* @return*/public int lengthOfLIS2(int[] nums) {if (nums == null || nums.length == 0) {return 0;}int n = nums.length;int[] dp = new int[n];dp[0] = 1; // 单个元素本身就是一个长度为 1 的连续递增子序列int res = 1; // 初始化结果为 1for (int i = 1; i < n; i++) {if (nums[i] > nums[i - 1]) {dp[i] = dp[i - 1] + 1;} else {dp[i] = 1; // 当前元素本身可以作为一个新的连续递增子序列的起点}res = Math.max(res, dp[i]); // 更新最长子序列的长度}return res;}

时间复杂度:(O(n))
空间复杂度:(O(n))

二,升级:求最长递增子序列

nums = [10,9,2,5,3,7,101,18]

求上面数组中的最长递增子序列,输出其长度

将上面一道题进行稍微变化一下,我们可以看出,现在的结果应该是2,3,7,101。输出结果应该是4。

如果不用动态规划,这道题有点难解。需要用到回溯+记忆,单纯的暴力解法并不适用。

比如我再加一个测试用例

nums =[0,1,0,3,2,3]

 回溯法
    /*** 方法一: 暴力解法* @param nums* @return*/public int lengthOfLIS(int[] nums) {if (nums == null || nums.length == 0) return 0;int maxLen = 0;for (int i = 0; i < nums.length; i++) {maxLen = Math.max(maxLen, backtrack(nums, i, new ArrayList<>()));}return maxLen;}// 回溯法生成所有递增子序列private int backtrack(int[] nums, int index, List<Integer> current) {if (index >= nums.length) return current.size();int maxLen = current.size();  // 不选当前元素的默认长度// 选择当前元素的情况if (current.isEmpty() || nums[index] > current.get(current.size() - 1)) {current.add(nums[index]);int lenWith = backtrack(nums, index + 1, current);current.remove(current.size() - 1);maxLen = Math.max(maxLen, lenWith);}// 不选当前元素的情况int lenWithout = backtrack(nums, index + 1, current);return Math.max(maxLen, lenWithout);}

时间复杂度: (O(2^n))

空间复杂度:O(n)

该方法容易超过时间限制

动态规划

这个就需要在上个动态规划样例中稍微改动一下。

我们先模拟一下对照样例生成的dp数组应该的样子。

int[] nums = {10, 9, 2,  5, 3, 7, 101, 18};
int[] dp =   {1,  1, 1,  2, 2, 3,  4,  4};

先举个简单的方便观察的例子

int[] nums = {1, 2, 3, 4, 2, 6, 7};
int[] dp =   {1, 2, 3, 4, 1, 5, 6};

即便当数组为递减数组时,长度也会输出1

  1. 所以我们还是需要先将dp数组全部初始化1
  2. 第一次遍历,2 > 1的,所以dp[1] = dp[0] + 1;
  3. 第二次遍历,3 > 1的,所以dp[2] = dp[0] + 1; 然后 3 > 2的,所以 dp[2] = dp[1] + 1;
  4. ……
  5. 第五次遍历,6 > 4的,所以dp[5] = dp[3] + 1;但是6 > 2,不能得出dp[5] = dp[4] + 1,需要dp[4] + 1与当前的dp[5]的值进行比较。取最大的一个。
  6. ……

所以综上我们可以写出代码

    /*** 方法二: 动态规划求解递增子序列* @param nums* @return*/public int lengthOfLIS2(int[] nums) {if (nums == null || nums.length == 0) {return 0;}int n = nums.length;int[] dp = new int[n];Arrays.fill(dp, 1);int res = 1; // 初始化结果为 1for (int i = 1; i < n; i++) {for (int j = 0; j < i; j++) {if (nums[j] < nums[i]) {dp[i] = Math.max(dp[i], dp[j] + 1);}res = Math.max(res, dp[i]);}}return res;}

 时间复杂度为 ​O(n²),空间复杂度为 ​O(n)。

三,再升级:删除最少元素,使剩余元素先递增后递减

动态规划

还是以刚刚的例子为例

nums = [10,9,2,5,3,7,101,18]

删除最少元素,使剩余元素先递增后递减,输出最少需要删除多少元素。

 通过上面两个例子,我们可以看出一个dp数组只能保存一个状态。

对于这道题,我们可以考虑使用两个dp数组来完成。

nums = [10,9,2,5,3,7,101,18]
int[] dp1 =   {1,  1, 1,  2, 2, 3,  4,  4}; //递增dp
int[] dp2 =   {4,  3, 1,  2, 1, 1,  2,  1}; //递减dp

 可以看出在dp1[6] + dp2[6] = 6的时候是最大的,所以最大长度应该是dp1[6] + dp2[6] - 1 = 5;

因为6这个节点重复计算了,所以需要减1

那么就能得出答案需要删除:nums.length() - 5 = 3;

最少需要删除3个元素。

    /*** 方法二: 动态规划求解删除最少元素,使剩余元素先递增后递减* @param nums* @return*/public int lengthOfLIS3(int[] nums) {if (nums == null || nums.length == 0) {return 0;}int n = nums.length;int[] dp1 = new int[n];int[] dp2 = new int[n];Arrays.fill(dp1, 1);Arrays.fill(dp2, 1);// 递增子序列for (int i = 1; i < n; i++) {for (int j = 0; j < i; j++) {if (nums[j] < nums[i]) {dp1[i] = Math.max(dp1[i], dp1[j] + 1);}}}// 递减子序列for (int i = n - 2; i >= 0; i--) {for (int j = n - 1; j > i; j--) {if (nums[j] < nums[i]) {dp2[i] = Math.max(dp2[i], dp2[j] + 1);}}}// 合并int max = 0;for (int i = 0; i < n; i++) {if (dp1[i] + dp2[i] > max) {max = dp1[i] + dp2[i];}}return n - max - 1;}

 四,看一道力扣原题

322. 零钱兑换

 这道题可以换个角度看看,我们要求amount的最小硬币个数。可以构建dp[amount + 1]数组,

求从1 - amount间的所有最小个数。

换个简单的实例

输入:coins = [1, 2], amount = 5

以外层coins为循环,内层循环amount得到最小值

如上面例子。

初始化dp数组,因为要求最小,所以初始值应该为最大,且dp[0] = 0;

第一次外层循环1得到dp数组[0,1,2,3,4,5]

第二次外层循环2得到dp数组[0,1,1,2,2,3]

构建dp公式:

dp[i] = Math.min(dp[i], dp[i - coin] + 1);

 得到解法

    public int coinChange(int[] coins, int amount) {int[] dp = new int[amount + 1];Arrays.fill(dp, amount + 1); // 初始化为不可达标记dp[0] = 0; // 基础情况// 外层循环遍历硬币for (int coin : coins) {// 内层循环遍历金额(完全背包正序遍历)for (int i = coin; i <= amount; i++) {dp[i] = Math.min(dp[i], dp[i - coin] + 1);}}return dp[amount] > amount ? -1 : dp[amount];}

http://www.dtcms.com/wzjs/151297.html

相关文章:

  • 公众号编辑器哪个好优化关键词排名提升
  • asp.net网站建设论文百度如何搜索网址
  • 上海建网站手机app电商网站链接买卖
  • 做网站需要什么设备跨境电商靠谱吗
  • wordpress用多大主机西安seo网站关键词
  • 个人怎样建立网站aso优化app推广
  • 关键词你们懂的优化营商环境心得体会个人
  • 机械产品做哪个网站seo费用
  • 北京网站关键词排名推广关键词什么意思
  • 泰州外贸网站设计搜狗网站提交入口
  • 移动互联和网站开发网络推广seo
  • 个人网上银行广西seo经理
  • 新手做网站看什么书推广哪个app最挣钱
  • h5网站如何做描述建设一个网站的具体步骤
  • 国外优惠卷网站如何做中国目前最好的搜索引擎
  • java小说网站开发百度seo快排软件
  • 好用的网站模板百度搜索趋势
  • ftp上传网站之后怎么做在线培训平台
  • 网站建设工程杭州搜索引擎排名
  • 天辰建设信息网东莞百度推广优化
  • 企业网站icp备案申请seo难不难学
  • 网站建设专业英文长沙靠谱关键词优化服务
  • 宽屏营销型网站源码百度指数上多少就算热词
  • 如何选择镇江网站建设青岛seo代理计费
  • 湛江网站建设方案推广开源seo软件
  • 做数学ppt工具的网站seo问答
  • 三亚网站开发公司网络营销发展现状与趋势
  • 旅游网站建设规划报告怎么写网站建设免费
  • 电商网站如何做多语言架构百度搜索广告投放
  • 高端网站制作 专业制作平台色盲测试图片60张