BUGAWAY算法小抄-时间开销为O(k^n)的一类动态规划问题

131. 分割回文串

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串。返回 s 所有可能的分割方案。

示例 1:

输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]

示例 2:

输入:s = "a"
输出:[["a"]]

提示:

  • 1 <= s.length <= 16
  • s 仅由小写英文字母组成

✏️ 题解

class Solution {
    private List<List<String>> res = new ArrayList<>();

    public List<List<String>> partition(String s) {
        // k^n的动态规划问题
        // 回溯 + 动态规划预处理
        // 动态规划预处理的是回文串(动规预处理这里有点难,要思考一下)
        // dp[i][j]表示字符串 s[i...j]是否是回文
        // dp[i][j] = true when i >= j
        // dp[i][j] = (s[i] == s[j]) && dp[i+1][j-1]
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        // 初始化
        for (int i = 0; i < n; i++) {
            Arrays.fill(dp[i], true);
        }
        for (int i = n - 1; i >= 0; --i) {
            for (int j = i + 1; j < n; ++j) {
                dp[i][j] = (s.charAt(i) == s.charAt(j)) && dp[i + 1][j - 1];
            }
        }
        dfs(s, 0, new ArrayList<String>(), dp);

        return res;
    }

    // public boolean isPalindrome(String s) {
    // // 双指针常见做法判断字符串是否是回文串
    // // 在该题的缺点是容易重复判断
    // // if (s.length() == 0 || s.length() == 1)
    // // return true;
    // // int i = 0, j = s.length() - 1;
    // // while (i < j) {
    // // if (s.charAt(i) != s.charAt(j))
    // // return false;
    // // i++;
    // // j--;
    // // }
    // // return true;
    // }

    public void dfs(String s, int i, List<String> ans, boolean[][] dp) {
        int n = s.length();
        if (i == n) {
            res.add(new ArrayList<String>(ans));
            return;
        } else {
            for (int j = i; j < n; j++) {
                if (dp[i][j]) {
                    ans.add(s.substring(i, j + 1));
                    dfs(s, j + 1, ans, dp);
                    ans.remove(ans.size() - 1);
                }
            }
        }
    }

}

787. K 站中转内最便宜的航班

n 个城市通过一些航班连接。给你一个数组 flights ,其中 flights[i] = [fromi, toi, pricei] ,表示该航班都从城市 fromi 开始,以价格 pricei 抵达 toi

现在给定所有的城市和航班,以及出发城市 src 和目的地 dst,你的任务是找到出一条最多经过 k 站中转的路线,使得从 srcdst价格最便宜 ,并返回该价格。 如果不存在这样的路线,则输出 -1

示例 1:

输入: 
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 1
输出: 200
解释: 
城市航班图如下
从城市 0 到城市 2 在 1 站中转以内的最便宜价格是 200,如图中红色所示。

img

示例 2:

输入: 
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 0
输出: 500
解释: 
城市航班图如下
从城市 0 到城市 2 在 0 站中转以内的最便宜价格是 500,如图中蓝色所示。

img

提示:

  • 1 <= n <= 100
  • 0 <= flights.length <= (n * (n - 1) / 2)
  • flights[i].length == 3
  • 0 <= fromi, toi < n
  • fromi != toi
  • 1 <= pricei <= 104
  • 航班没有重复,且不存在自环
  • 0 <= src, dst, k < n
  • src != dst

🐧 腾讯 2024 技术岗春招笔试第四题

小红拿到了一个数组,她准备将数组分割成 k 段,使得每段内部做按位异或后,再全部求和。小红希望最终这个和尽可能大,你能帮帮她吗?

示例 1:

输入:arr = [1,1,1,2,3,4], k=2
输出:10
说明:分割方式:[1,1,1,2 | 3,4]

这道题和上面的有异曲同工之妙。(因为是笔试真题,没找到所有原题样例,只记得一个样例)

import java.util.Scanner;

public class Demo84 {
    // 动态规划 f[i][cnt] 表示[i, n-1]分割 k-cnt 段能产生的最大和 return f[0][0]
    // 初始化最后一排为0,最后一列为0 内外层都是从后往前遍历
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int k = in.nextInt();
        int[] arr = new int[n];
        int[] sum = new int[n + 1]; // 异或前缀和
        for (int i = 0; i < n; i++) {
            arr[i] = in.nextInt();
            sum[i + 1] = sum[i] ^ arr[i];
        }
        long[][] f = new long[n + 1][k + 1];
				for (int i = 0; i < n; i++) {
          for (int j = 0; j <= i; j++) {
              for (int s = 1; s <= k; s++) {
                  f[i][s] = max(f[i][s], f[j][s - 1] + (sum[i + 1] ^ sum[j + 1]));
              }

          }
				}
        System.out.println(f[0][0]);
    }
}

posted @ 2024-04-02 11:19  无发可说  阅读(15)  评论(0编辑  收藏  举报