算法复习
算法填空题
子集生成
给定一个正整数集合X={x1,x2, … , xn}和一个正整数y,设计一个回溯算法求集合x的一个子集Y,使得Y中的元素之和等于y
算法如下:
输入:数组x,解向量p,开始下标from,目标y
输出:true或者false
1.若X[from]等于y,则p[from] = 1,返回ture//找到解
2.若X[from]大于y,则p[from] = 0,返回false//剪枝回溯
3.置p[from] = 1
3.1调用本算法,参数X,p,from+1,y-X[from];
3.2若算法返回true,则找到一组解,返回true
4.置p[from] = 0
4.1调用本算法,参数X,p,from+1,y
4.2若算法返回true,则找到一组解,返回true
代码:
public boolean reverse(int[] X,boolean[] p,int from,int y){
if(X[from] == y){
p[from] = true;
return true;
}
if(X[from] > y){
p[from] = false;
return fasle;
}
p[from] = true;
if(reverse(X,p,from+1,y-X[from]))
return true;
p[from] = false;
if(reverse(X,p,from+1,y))
return true;
}
全排列生成
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
算法如下:
全局变量:数组P存放符合条件的结果,对象数组result,存放结果,used Boolean[]数组,判断是否使用过
输入:数组X
输出:无
1:若数组P的长度等于X的长度,则将数组P添加到result数组中
2:循环遍历数组X[i]
2.1如果used[i]为真,则continue
2.2把used[i]置为真,并且将X[i]添加到P中
2.3再次调用本算法
2.4将X[i]从P中移除,将used置为false
class Solution {
List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
LinkedList<Integer> path = new LinkedList<>();// 用来存放符合条件结果
boolean[] used;
public List<List<Integer>> permute(int[] nums) {
if (nums.length == 0){
return result;
}
used = new boolean[nums.length];
permuteHelper(nums);
return result;
}
private void permuteHelper(int[] nums){
if (path.size() == nums.length){
result.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < nums.length; i++){
if (used[i]){
continue;
}
used[i] = true;
path.add(nums[i]);
permuteHelper(nums);
path.removeLast();
used[i] = false;
}
}
}
最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。
用动态规划法求两个字符串A=”xzyzzyx”
和B=”zxyyzxz”
的最长公共子序列。写出求解过程。
设的最长公共子序列的长度。动态规划函数定义为:
状态矩阵定义为:
长度矩阵、状态矩阵如下:
B |
z | x | y | y | z | x | z | ||
---|---|---|---|---|---|---|---|---|---|
A |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
x | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
z | 2 | 0 | 1 | 1 | 1 | 1 | 2 | 2 | 2 |
y | 3 | 0 | 1 | 1 | 2 | 2 | 2 | 2 | 2 |
z | 4 | 0 | 1 | 1 | 2 | 2 | 3 | 3 | 3 |
z | 5 | 0 | 1 | 1 | 2 | 2 | 3 | 3 | 4 |
y | 6 | 0 | 1 | 1 | 2 | 3 | 3 | 3 | 4 |
x | 7 | 0 | 1 | 2 | 2 | 3 | 3 | 4 | 4 |
长度矩阵L
B |
z | x | y | y | z | x | z | ||
---|---|---|---|---|---|---|---|---|---|
A |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
x | 1 | 0 | 0 | 1 | 2 | 2 | 2 | 2 | 2 |
z | 2 | 0 | 1 | 2 | 2 | 2 | 1 | 3 | 1 |
y | 3 | 0 | 3 | 2 | 1 | 1 | 2 | 3 | 2 |
z | 4 | 0 | 1 | 2 | 3 | 2 | 1 | 2 | 1 |
z | 5 | 0 | 1 | 2 | 3 | 2 | 1 | 2 | 1 |
y | 6 | 0 | 3 | 2 | 1 | 1 | 2 | 2 | 3 |
x | 7 | 0 | 3 | 1 | 2 | 3 | 2 | 1 | 2 |
状态矩阵S
由长度矩阵可知,A和B的最大公共子序列长度为4。最大公共子序列为:xyyx、xyzx、zyyx、xyzz、zyzz等。
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int[][] dp = new int[text1.length() + 1][text2.length() + 1]; // 先对dp数组做初始化操作
for (int i = 1 ; i <= text1.length() ; i++) {
char char1 = text1.charAt(i - 1);
for (int j = 1; j <= text2.length(); j++) {
char char2 = text2.charAt(j - 1);
if (char1 == char2) { // 开始列出状态转移方程
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[text1.length()][text2.length()];
}
}
最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
动态规划函数定义为:
L(i)=max(L(i-1)+nums[i],nums[i])
输入:nums = [-2,1,-3,4,-1,2,1,-5,4],对应的状态如下
状态矩阵:
public static int maxSubArray(int[] nums) {
if (nums.length == 0) {
return 0;
}
int res = nums[0];
int[] dp = new int[nums.length];
dp[0] = nums[0];
for (int i = 1; i < nums.length; i++) {
dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
res = res > dp[i] ? res : dp[i];
}
return res;
}