矩阵与动态规划相关

目录

  • 54/59螺旋矩阵
  • 62不同路径
  • 64最小路径和
  • 120三角形最小路径和
  • 695岛屿的最大面积
  • 547朋友圈
  • 718最长重复数组
  • 221最大正方形
  • 121/122/123/714/188买卖股票的最佳时机
  • 416分割等和子集
  • 01背包/最近等分子集
  • 70爬楼梯

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]
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)

原文地址:https://www.cnblogs.com/code2one/p/10100188.html

时间: 2024-07-29 04:08:26

矩阵与动态规划相关的相关文章

matlab矩阵合并及相关运算

1.matlab允许向量(和矩阵)合并,且matlab提供了两种合并方式,[a,b]和[a;b],两者的结果是不一样的. a=rand(2,3): b=rand(2,3): c=[a;b]: d=[a,b]: c的结果是将b整体合并到a 的下边,而d的结果是整体将b合并到a 的右边. 2.创建等差向量组 a=[1:2:11] 注意涉及到向量内部对应数据之间的运算时一定要用点运算符号,(.)例如,求表达式b=a^2时应该写作 b=a.^2 也可以利用linspace来创建等差向量,linspace

poj1651 最优矩阵乘法动态规划解题

题目描述: 有若干个矩阵{Ai},元素都为整数且已知矩阵大小. 如果要计算所有矩阵的乘积A1 * A2 * A3 .. Am,最少要多少次整数乘法? 输入 第一行一个整数n(n <= 100),表示一共有n-1个矩阵.第二行n个整数B1, B2, B3... Bn(Bi <= 100),第i个数Bi表示第i个矩阵的行数和第i-1个矩阵的列数.等价地,可以认为第j个矩阵Aj(1 <= j <= n - 1)的行数为Bj,列数为Bj+1. 输出 一个整数,表示最少所需的乘法次数 采用动

动态规划相关问题学习笔记

转载自:http://blog.csdn.net/speedme/article/details/24231197 1. 什么是动态规划 ------------------------------------------- dynamic programming is a method for solving complex problems by breaking them down into simpler subproblems. (通过把原问题分解为相对简单的子问题的方式求解复杂问题的

小奇的矩阵(动态规划

[题目 背景] 小奇总是在数学课上思考奇怪的问题. [问题描述] 给定一个 n*m 的矩阵, 矩阵中的每个元素 aij 为正整数. 接下来规定 1. 合法的路径初始从矩阵左上角出发, 每次只能向右或向下走, 终点为右下 角. 2. 路径经过的 n+m-1 个格子中的元素为 A1, A2…A(n+m-1) , Aavg 为 Ai 的平 均数, 路径的 V 值为(n+m-1) *∑ (Ai-Aavg) ^2 (1<=i<=n+m-1) 求 V 值最小的合法路径, 输出 V 值即可, 有多组测试数据

矩阵相关

目录 矩阵前置芝士 矩阵加法: 矩阵减法: 矩阵乘法: 矩阵快速幂 斐波那契数列 矩阵递推相关 矩阵快速幂优化DP 矩阵前置芝士 矩阵:看成一个二维数组就好了. 矩阵加法: 本人认为没用 条件:两个大小相同的矩阵 对应位置相加,形成相同大小的矩阵. 矩阵减法: 本人认为没用 条件:两个大小相同的矩阵 对应位置相减,形成相同大小的矩阵. 矩阵乘法: 这个很重要 条件:两个大小不完全一样的矩阵,必须保证矩阵\(A(n*k)\),矩阵B大小是\(k*m\)的,形成的矩阵C大小是\(n*m\)的 C矩阵

数据结构——动态规划

前言 “动态规划”在大一时,就知道了这个词,当时觉得好难好高大上,从此心生畏惧,闻词色变,心理阴影一直留存到现在. 在校招时,也多次被问到动态规划相关的题目. 本篇从一道经典动态规划题目说起,慢慢展开. 从题目讲起 [换钱的方法数] 给定数组 arr,arr 中所有的值都为正数且不重复.每个值代表一种面值的货币,每种面值的货币都可以使用任意张,再给定一个整数 aim 代表要找的钱数,求换钱有多少种方法. [举例] arr = [5, 10, 25, 1],aim = 15 则组成 15 元的方法

每日算法之四十一:Spiral Matrix II (螺旋矩阵)

Given an integer n, generate a square matrix filled with elements from 1 to n2 in spiral order. For example, Given n = 3, You should return the following matrix: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ] 针对这个问题采用最直观的方式即可,即螺旋插入,这里有两个地方需要注意,一个是插入边界的界定,

动态规划网络资料收集

之前在学习如何写hoj 1003 的时候,由于不懂动态规划,所以把动态规划相关内容智力学习了一下,虽然对我来说,学会1003和看明白跟动态规划没有什么比较大的关系,但对之前收集的资料做一下整理也好. 首先,什么是动态规划,如何理解动态规划 知乎徐凯强的答案很有“总纲”的感觉 https://www.zhihu.com/question/23995189/answer/35324479 王勐 也说的很清楚 https://www.zhihu.com/question/23995189/answer

【原创】开源Math.NET基础数学类库使用(二)矩阵向量计算

开源Math.NET系列文章目录: 1.开源.NET基础数学计算组件Math.NET(一)综合介绍  2.开源.NET基础数学计算组件Math.NET(二)矩阵向量计算  3.开源.NET基础数学计算组件Math.NET(三)C#解析Matlab的mat格式 4.开源.NET基础数学类库使用Math.NET(四)C#解析Matrix Marke数据格式 5.开源.NET基础数学类库使用Math.NET(五)C#解析Delimited Formats数据格式 6.开源.NET基础数学类库使用Mat