线性
感觉就是可以凭借一维数组就可以记录每个位置所需的情况,后面的数据会根据前面的推论得知
程序员爬楼
程序员对于每层楼可以爬一层也可以爬三层,问第n层有几种爬楼情况
每一层的爬层要么是上一层直接爬一层,要么是上三层爬三层,所以情况就是 arr[i-1] + arr[i-3]
public static void climbFloor() {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] methods = new int[n + 1];
methods[0] = 1;
methods[1] = 1;
methods[2] = 1;
methods[3] = 2;
for (int i = 4; i <= n; i++) {
methods[i] = methods[i - 1] + methods[i - 3];
}
System.out.println(methods[n]);
}
硬币情况
就是给定一些已有的硬币,让你求出某个面值最少会被多少硬币表示出来
public static int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1]; // 有初始0,所以数组要多一
for (int i = 1; i <= amount; i++) {
dp[i] = -1;
for (int coin : coins) {
if (i == coin) { // 如果索引等于对应的面值的话,那么就是本身一张就够了
dp[i] = 1;
} else if (i > coin && dp[i - coin] != -1) {
// 如果索引大于现有的面值,并且对应的去掉此面额的coin已知的找零数量已经确定了
if (dp[i] == -1) { // 如果dp[i]还是-1,说明还没有被赋值过,那么就直接赋值
dp[i] = dp[i - coin] + 1; // 此时的dp[coin]是1,因为coin就是本身
// 就相当于去掉已有coin的面额的情况加上coin即可
} else { // 如果dp[i]不是-1,说明已经被赋值过了,那么就要取最小值
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}
}
}
return dp[amount];
}
最长上升子序列
给出一行内容,求出最长的上升子序列的长度或值
默认不重复
public static void zuichangshangshengzixulie() {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
int[] dp = new int[n]; // 存的就是某一位置上所能保持的最长长度
dp[0] = 1;
// 初始都设置为0
int max = 1;
// 默认最大就是1呗
for (int i = 1; i < n; i++) {
// 外层遍历所有的元素
dp[i] = 1;
for (int j = 0; j < i; j++) {
// 内层遍历在这个数之前的所有元素
// 如果arr[i]大于arr[j],说明arr[i]可以接在arr[j]后面形成一个更长的上升子
// 序列。这时,dp[i] 被更新为 dp[j] +1 和当前 dp[i] 的较大值。
if (arr[i] > arr[j]) { // 外层的值大的时候,就说明之前的位置+1,但是要取最大的
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
max = Math.max(max, dp[i]);
}
System.out.println(max);
// System.out.println(Arrays.toString(dp));
}
public static int maxl(int[] nums, int t){ // 返回大于等于某个数的最小位置的方法。有序
int n = nums.length;
int l = 0;
int r = n - 1;
int mid = 0;
while (l <= r){
mid = l + (r - l) / 2;
if (nums[mid] < t){
l = mid + 1;
} else {
r = mid - 1;
}
}
return l;
}
// 暂时不理解
public int lengthOfLIS(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int[] tails = new int[nums.length];
int size = 0;
for (int num : nums) {
int left = 0, right = size;
while (left != right) {
int mid = left + (right - left) / 2;
if (tails[mid] < num) {
left = mid + 1;
} else {
right = mid;
}
}
tails[left] = num;
if (left == size) {
size++;
}
}
return size;
接龙序列
直接拿整体的长度减去最长接龙序列的值即可
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
int[] dp = new int[11]; // 这个表示以某个数字结尾的最长子序列的长度
// 可能以0结尾
for (int i = 0; i < n; i++) {
String s = arr[i] + "";
int head = s.charAt(0) - '0'; // 表示此时的头是什么数
int tail = s.charAt(s.length() - 1) - '0'; // 表示此时的尾是什么数
// 以tail结尾的最长子序列的长度,就是以head结尾的最长子序列的长度+1
// 为啥是呢,是因为自己的头符合别人的尾了,此时自己的头实际上是最长序列的尾,所以要找一个更长的值啊
// 自己的头符合条件的话,就相当于以自己头结尾的值要+1
dp[tail] = Math.max(dp[tail], dp[head] + 1);
}
// System.out.println(Arrays.toString(dp));
Arrays.sort(dp);
// System.out.println(Arrays.toString(dp));
System.out.println(n - dp[10]);
}
本文介绍了四个编程问题,涉及线性动态规划解决方案:计算不同爬楼方式的总数、用最少硬币表示特定金额、求最长上升子序列长度以及计算接龙序列长度。通过递推关系展示了如何利用动态规划思想解决这些问题。






