leetcode矩阵与动态规划相关
54/59螺旋矩阵
思路:
- 设置上下左右四个边界变量
- 新建ArrayList存储结果
- 循环:四个循环,左->右,上->下,右->左,下->上。每次循环添加结果,循环后判断边界是否相等了,是的话就退出
// 设置边界变量
int m = matrix.length, n = matrix[0].length;
int left = 0, right = n - 1, up = 0, down = m - 1;
// 循环,注意right = n - 1,所以遍历范围i <= right
while (true){
for (int i = left; i <= right; i++){
res.add(matrix[up][i]);
// 获取回旋矩阵的话用 res[up][i] = val++;
}
if (++up > down) break;
for (int i = up; i <= down; i++){
res.add(matrix[i][right]);
}
if (--right < left) break;
for (int i = right; i >= left; i--){
res.add(matrix[down][i]);
}
if (--down < up) break;
for (int i = down; i >= up; i--){
res.add(matrix[i][left]);
}
if (++left > right) break;
}
62不同路径
一个机器人位于一个 m x n 网格的左上角 。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。
思路:画图
int[] dp = new int[n];
dp[0] = 1;
for (int i = 0; i < m; ++i) {
for (int j = 1; j < n; ++j) {
dp[j] += dp[j - 1];
}
}
return dp[n-1];
64最小路径和
与上面未经优化的代码有点像。
思路:
- 新建dp,填充起步数值。
- 第一个值为grid[0][0]
- 第一行和列通过前一个格子和grid的对应值的和来填充
- 遍历
- dp[i][j]的值为grid的对应值加上上一步dp的最小值
int m = grid.length, n = grid[0].length;
int[][] dp = new int[m][n];
dp[0][0] = grid[0][0];
for (int i = 1; i < m; ++i) dp[i][0] = grid[i][0] + dp[i - 1][0];
for (int i = 1; i < n; ++i) dp[0][i] = grid[0][i] + dp[0][i - 1];
for (int i = 1; i < m; ++i) {
for (int j = 1; j < n; ++j) {
dp[i][j] = grid[i][j] + Math.min(dp[i - 1][j], dp[i][j - 1]);
}
}
return dp[m - 1][n - 1];
120三角形最小路径和
思路:
- 新建数组,复制最后一行
- 循环
- 将第一个数改为第一个数与第二个数的最小值加下上一行的第一个数,第二个数改为第二个数与第三个数的最小值加上一行第二个数,如此类推。
要注意的是下面j的范围j <= i
for (int i = n - 2; i >= 0; i--){
for (int j = 0; j <= i; j++){
dp[j] = Math.min(dp[j], dp[j+1]) + m.get(i).get(j);
}
}
695岛屿的最大面积
思路:
- 遍历二维数组
- 如果当前数值==1,说明是岛屿,而且没有遍历过,此时调用helper计算这个岛屿的面积,并根据返回结果更新res
- helper函数
- 检查岛屿坐标的合法性,没有超边界和数值==1(后续调用需要检查)
- 把当前岛屿值变为0,说明已经遍历
- return 1+对四个方位调用helper
547朋友圈
思路:
- 新建一个visited数据记录已被遍历的人
- 开始遍历,如果这个人还没被遍历过,那么就是一个新的朋友圈,cnt++,然后调用helper递归搜索这个人的朋友。
- helper,先把遍历到的人在visited中设置为true,然后遍历这个人的行,如果是朋友,且这个人没有被遍历过,那么就递归调用helper。
// 设置人数变量、朋友圈数计算器
int n = M.length, cnt = 0;
// 记录visited的人的数组
boolean[] visited = new boolean[n];
// 按顺序遍历每个人,如果没有访问过才开始调用helper
for (int i = 0; i < n; i++){
// 如果未访问过,就调用helper
if (!visited[i]){
helper(M, i, visited);
// 遍历一次,朋友圈数 +1
cnt++;
}
}
return cnt;
// helper
visited[k] = true;
// 遍历这个人的朋友
for (int i = 1; i < m.length; i++){
// 如果这个人是朋友,而且没有访问过,那就调用helper
if (m[k][i] == 1 && !visited[i]){
helper(m, i, visited);
}
}
718最长重复数组
输入:
A: [1,2,3,2,1]
B: [3,2,1,4,7]
输出: 3
解释:
长度最长的公共子数组是 [3, 2, 1]。
思路:
- 递推公式为
dp[j] = A[i] == B[j] ? dp[j-1] + 1 : 0
。然后画图,先画二维,再到一维。
221最大正方形
思路:
- 新建与参数一样大小的dp
- 遍历填充
if (i == 0 || j == 0) dp[i][j] = matrix[i][j] - '0';
else if (matrix[i][j] == '1') {
dp[i][j] = 当前dp左上,上,左的最小值 + 1;
}
res = Math.max(res, dp[i][j]);
return res * res;
121/122/123/714/188买卖股票的最佳时机
121:只允许一笔交易
122:允许多笔交易
123:只允许两笔交易
714:允许多笔交易,包含手续费
188:只允许k笔交易
int sell = 0, buy = Integer.MIN_VALUE + free; // free为714,防止第一步溢出
for (int price : prices){
// 第二个 sell 表示第i天前最后一个操作是卖,此时的最大收益。第一步的sell肯定得到0
sell = Math.max(sell, price + buy - free); // free为714
// 121
// buy = Math.max(buy, 0 - price);
// 122
buy = Math.max(buy, sell - price);
}
return sell;
// 123
int buy1 = Integer.MIN_VALUE, sell1 = 0;
int buy2 = Integer.MIN_VALUE, sell2 = 0;
for (int price : prices) {
// 这里要倒排,因为sell2是依赖之前的buy2数据,buy2依赖之前的sell1数据,如此类推
sell2 = Math.max(sell2, buy2 + price);
buy2 = Math.max(buy2, sell1 - price);
sell1 = Math.max(sell1, buy1 + price);
buy1 = Math.max(buy1, 0 - price); // max寻找最低购入价,第一步buy的sell都是0
}
return sell2;
// 188
if (k > prices.length) {
// 122代码
}
// 下面代码把k改为2,就是123的答案
int[] buyArr = new int[k+1];
int[] sellArr = new int[k+1];
Arrays.fill(buyArr,Integer.MIN_VALUE);
for (int price : prices) {
for (int i = k; i > 0; i--) {
sellArr[i] = Math.max(sellArr[i], price + buyArr[i]);
buyArr[i] = Math.max(buyArr[i], sellArr[i-1] - price);
}
}
return sellArr[k];
416分割等和子集
判断数组中的数是否可以被分割成两份和相等的子集
思路:
- 累加判断子集和是否为偶数,不是偶数就已经不可能等分了
- 总和/2作为目标值,并新建boolean dp[target+1]
- 遍历
- 递推思想:当前dp是否为true,取决于之前是否已经可以组成i,或者考虑上当前遍历的num就能等于i。公式为:
dp[i] = dp[i] || dp[i - num]
- 递推思想:当前dp是否为true,取决于之前是否已经可以组成i,或者考虑上当前遍历的num就能等于i。公式为:
int sum = 0;
for (int num : nums) sum += num;
if ((sum & 1) != 0) return false;
int target = sum >> 1;
// dp[i]表示上面解法的 j ,即前面所有元素的组合的"和"是否能够等于i
boolean[] dp = new boolean[target + 1];
dp[0] = true;
for (int num : nums) {
// 直接从num开始,因为考虑了num,那么其组合最小也等于num
for (int i = target; i >= num ; i--) {
dp[i] = dp[i] || dp[i - num];
}
}
return dp[target];
01背包/最近等分子集
01背包
思路:
递推公式f[i][j] = Math.max(f[i - 1][j - w[i - 1]] + p[i - 1], f[i - 1][j]);
取和不取第i个物品的最大值作为f[i][j]。从公式中可知,没有j-1,所以dp在j的维度上不需要1。另外,公式中考虑了i-1,所以dp在i维度上要+1,而i=1时所考虑的0,即没有考虑任何物品,所以dp值自然都是0,不需要另外初始化。由于只考虑i-1,所以可以用一维的dp,每次更新dp时,其本身的值就是之前的值。要注意的是j的起始值为当前物品的重量,因为小于这个重量,就不可能考虑加入这个物品了。最后,由于j - w[i - 1]
,说明j要考虑之前的值,所以1维的覆盖要从后往前。
int[] dp = new int[capacity];
for (int i = 0; i < n; i++) {
for (int j = capacity-1; j >= w[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - w[i]] + p[i]);
}
}
return dp[capacity-1];
最近等分子集
思路:
- 累加子集然后除以二得target。目标是让选取的子集的和尽可能接近targe。类比上题可得优化后的递推公式为
dp[i] = Math.max(dp[i - num] + num, dp[i]);
与“416分割等和子集”一样的方式得出target,由于取最接近,所以不需要判断可能性。dp也类似,选取的是i代表子集中所考虑的与
for (int num : arr) {
for (int i = target-1; i >= num; i--) {
dp[i] = Math.max(dp[i - num] + num, dp[i]);
}
}
return sum - 2 * dp[target-1];
70爬楼梯
f(x) = f(x-1) + f(x-2)
leetcode矩阵与动态规划相关的更多相关文章
- LeetCode: Palindrome 回文相关题目
LeetCode: Palindrome 回文相关题目汇总 LeetCode: Palindrome Partitioning 解题报告 LeetCode: Palindrome Partitioni ...
- LeetCode总结 -- 一维动态规划篇
这篇文章的主题是动态规划, 主要介绍LeetCode中一维动态规划的题目, 列表如下: Climbing StairsDecode WaysUnique Binary Search TreesMaxi ...
- LeetCode初级算法--动态规划01:爬楼梯
LeetCode初级算法--动态规划01:爬楼梯 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net ...
- 【LeetCode题解】动态规划:从新手到专家(一)
文章标题借用了Hawstein的译文<动态规划:从新手到专家>. 1. 概述 动态规划( Dynamic Programming, DP)是最优化问题的一种解决方法,本质上状态空间的状态转 ...
- C#LeetCode刷题-动态规划
动态规划篇 # 题名 刷题 通过率 难度 5 最长回文子串 22.4% 中等 10 正则表达式匹配 18.8% 困难 32 最长有效括号 23.3% 困难 44 通配符匹配 17.7% ...
- poj1651 最优矩阵乘法动态规划解题
题目描述: 有若干个矩阵{Ai},元素都为整数且已知矩阵大小. 如果要计算所有矩阵的乘积A1 * A2 * A3 .. Am,最少要多少次整数乘法? 输入 第一行一个整数n(n <= 100), ...
- LeetCode -- Word Break 动态规划,详细理解
Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separa ...
- LeetCode矩阵题型
以三角形遍历矩阵 ; i < matrix.size(); ++i) { ; j < matrix[i].size(); ++j) swap(matrix[i][j], matrix[j] ...
- LeetCode初级算法(动态规划+设计问题篇)
目录 爬楼梯 买卖股票的最佳时机 最大子序和 打家劫舍 动态规划小结 Shuffle an Array 最小栈 爬楼梯 第一想法自然是递归,而且爬楼梯很明显是一个斐波拉切数列,所以就有了以下代码: c ...
随机推荐
- Windows2008 Server 常规设置及基本安全策略
一.系统及程序 1.屏幕保护与电源 桌面右键--〉个性化--〉屏幕保护程序屏幕保护程序 选择无更改电源设置 选择高性能选择关闭显示器的时间 关闭显示器 选 从不 保存修改 2.安装IIS 管理工具-- ...
- VMware 11安装Mac OS X 10.10 及安装Mac Vmware Tools.
先上一张效果图兴奋一下,博主穷屌丝一个,只能通过虚拟黑苹果体验下高富帅的生活,感觉超爽的,废话不多说的,直接上图了! 目录: 1.安装所需软件下载: 2.Mac OS X10.10 安装基本步骤: 3 ...
- Python 之糗事百科多线程爬虫案例
import requests from lxml import etree import json import threading import queue # 采集html类 class Get ...
- 用C#在Visual Studio写Javascript单元测试(Firefox内核)
引用nuget包: 注意:Geckofx45 nuget包必须是最后引用,否则初始化会出错 编写JsRunner using Gecko; using System; using System.Col ...
- 远程连接阿里云服务器ping不通ip解决方案
搭建了阿里云服务器,发现本地ping不通,查看半天才发现,原来是在阿里云上的安全组少了些东西. 在出入方向上新建一个安全组,就可以搞定了.
- 安装低版本django1.11出错
错误信息: File "C:\python3\lib\site-packages\django\utils\autoreload.py", line 227, in wrapper ...
- oralce 创建表空间 和 查询进程
-- Create the user create user lesdba identified by les_321 default tablespace USERS temporary table ...
- (JS,JAVA,MySql)去除小数后多余的0
分别通过JS,JAVA和MySql实现去除小数后多余的0 1. JS方法 /** *去除小数点后多余的0 */ function cutZero(old) { //拷贝一份 返回去掉零的新串 old ...
- 44.bucket filter:统计各品牌最近一个月的平均价格
课程大纲 GET /tvs/sales/_search { "size": 0, "query": { "term": { &quo ...
- Xen、OpenVZ、KVM、Hyper-V、VMWare虚拟化技术介绍
一.Xen 官网:http://xen.org/ Xen 由剑桥大学开发,它是基于硬件的完全分割,物理上有多少的资源就只能分配多少资源,因此很难超售.可分为Xen-PV(半虚拟化),和Xen-HVM( ...