Leetcode_入门_分治
1、为运算表达式设计优先级(241、medium)
1)题目要求
给定一个含有数字和运算符的字符串,为表达式添加括号,改变其运算优先级以求出不同的结果。你需要给出所有可能的组合的结果。有效的运算符号包含 +, - 以及 * 。
示例 1:
输入: “2-1-1”
输出: [0, 2]
解释:
((2-1)-1) = 0
(2-(1-1)) = 2
示例 2:
输入: “23-45”
输出: [-34, -14, -10, -10, 10]
解释:
(2*(3-(45))) = -34
((23)-(45)) = -14
((2(3-4))5) = -10
(2((3-4)5)) = -10
(((23)-4)*5) = 10
2)我的解法
没想出来。。
3)其他解法
1、
class Solution {
public List<Integer> diffWaysToCompute(String input) {
return partition(input);
}
public List<Integer> partition(String input) {
List<Integer> result = new ArrayList<>();
if (!input.contains("+") && !input.contains("-") && !input.contains("*")) {
result.add(Integer.valueOf(input));
return result;
}
for(int i = 0; i < input.length(); i++) {
if (input.charAt(i) == '+' || input.charAt(i) == '-' || input.charAt(i) == '*') {
for(Integer left : partition(input.substring(0, i))) {
for (Integer right : partition(input.substring(i + 1))) {
if (input.charAt(i) == '+') {
result.add(left + right);
} else if (input.charAt(i) == '-') {
result.add(left - right);
} else if (input.charAt(i) == '*') {
result.add(left * right);
}
}
}
}
}
return result;
}
}
作者:thunder-zh
链接:link
来源:力扣(LeetCode)
2、记忆化
//添加一个 map
HashMap<String,List<Integer>> map = new HashMap<>();
public List<Integer> diffWaysToCompute(String input) {
if (input.length() == 0) {
return new ArrayList<>();
}
//如果已经有当前解了,直接返回
if(map.containsKey(input)){
return map.get(input);
}
List<Integer> result = new ArrayList<>();
int num = 0;
int index = 0;
while (index < input.length() && !isOperation(input.charAt(index))) {
num = num * 10 + input.charAt(index) - '0';
index++;
}
if (index == input.length()) {
result.add(num);
//存到 map
map.put(input, result);
return result;
}
for (int i = 0; i < input.length(); i++) {
if (isOperation(input.charAt(i))) {
List<Integer> result1 = diffWaysToCompute(input.substring(0, i));
List<Integer> result2 = diffWaysToCompute(input.substring(i + 1));
for (int j = 0; j < result1.size(); j++) {
for (int k = 0; k < result2.size(); k++) {
char op = input.charAt(i);
result.add(caculate(result1.get(j), op, result2.get(k)));
}
}
}
}
//存到 map
map.put(input, result);
return result;
}
private int caculate(int num1, char c, int num2) {
switch (c) {
case '+':
return num1 + num2;
case '-':
return num1 - num2;
case '*':
return num1 * num2;
}
return -1;
}
private boolean isOperation(char c) {
return c == '+' || c == '-' || c == '*';
}
3、动态规划
public List<Integer> diffWaysToCompute(String input) {
List<Integer> numList = new ArrayList<>();
List<Character> opList = new ArrayList<>();
char[] array = input.toCharArray();
int num = 0;
for (int i = 0; i < array.length; i++) {
if (isOperation(array[i])) {
numList.add(num);
num = 0;
opList.add(array[i]);
continue;
}
num = num * 10 + array[i] - '0';
}
numList.add(num);
int N = numList.size(); // 数字的个数
// 一个数字
ArrayList<Integer>[][] dp = (ArrayList<Integer>[][]) new ArrayList[N][N];
for (int i = 0; i < N; i++) {
ArrayList<Integer> result = new ArrayList<>();
result.add(numList.get(i));
dp[i][i] = result;
}
// 2 个数字到 N 个数字
for (int n = 2; n <= N; n++) {
// 开始下标
for (int i = 0; i < N; i++) {
// 结束下标
int j = i + n - 1;
if (j >= N) {
break;
}
ArrayList<Integer> result = new ArrayList<>();
// 分成 i ~ s 和 s+1 ~ j 两部分
for (int s = i; s < j; s++) {
ArrayList<Integer> result1 = dp[i][s];
ArrayList<Integer> result2 = dp[s + 1][j];
for (int x = 0; x < result1.size(); x++) {
for (int y = 0; y < result2.size(); y++) {
// 第 s 个数字下标对应是第 s 个运算符
char op = opList.get(s);
result.add(caculate(result1.get(x), op, result2.get(y)));
}
}
}
dp[i][j] = result;
}
}
return dp[0][N-1];
}
private int caculate(int num1, char c, int num2) {
switch (c) {
case '+':
return num1 + num2;
case '-':
return num1 - num2;
case '*':
return num1 * num2;
}
return -1;
}
private boolean isOperation(char c) {
return c == '+' || c == '-' || c == '*';
}
作者:windliang
链接:link
来源:力扣(LeetCode)
4)自己的优化代码
c++
class Solution {
public List<Integer> compute(String input){
List<Integer> result=new ArrayList<>();
if(!input.contains("+")&&!input.contains("-")&&!input.contains("*")){
result.add(Integer.parseInt(input));
}
else {
for(int i=0;i<input.length();i++){
if(input.charAt(i)=='+'||input.charAt(i)=='-'||input.charAt(i)=='*'){
for(Integer left:compute(input.substring(0,i))){
for(Integer right:compute(input.substring(i+1))){
if(input.charAt(i)=='-')result.add(left-right);
if(input.charAt(i)=='+')result.add(left+right);
if(input.charAt(i)=='*')result.add(left*right);
}
}
}
}
}
return result;
}
public List<Integer> diffWaysToCompute(String input) {
return compute(input);
}
}
5)学到的东西
分治算法,分成互不关联的小部分,最后合并
记忆化
根据记忆化推导出动态规划的思路
2、不同的二叉搜索树 II(95、Medium)
1)题目要求
给定一个整数 n,生成所有由 1 … n 为节点所组成的 二叉搜索树 。
示例:
输入:3
输出:
[
[1,null,3,2],
[3,2,null,1],
[3,1,null,null,2],
[2,1,3],
[1,null,2,null,3]
]
解释:
以上的输出对应以下 5 种不同结构的二叉搜索树:
1 3 3 2 1
\ / / / \
3 2 1 1 3 2
/ / \
2 1 2 3
提示:
0 <= n <= 8
2)我的解法
c++
class Solution {
public List<TreeNode> getTree(List<Integer> list){
List<TreeNode> result=new ArrayList<>();
if(list.size()==1&&list.get(0)==0){
TreeNode t=null;
result.add(t);
return result;
}
else if(list.size()==1){
result.add(new TreeNode(list.get(0)));
return result;
}
for(int i=0;i<list.size();i++){
List<Integer> small=new ArrayList<>();
List<Integer> big=new ArrayList<>();
for(Integer I:list){
if(I>list.get(i))big.add(I);
else if(I<list.get(i))small.add(I);
}
if(small.size()==0)small.add(0);
if(big.size()==0)big.add(0);
System.out.println("small"+small);
System.out.println("big"+big);
for(TreeNode b:getTree(big)){
for(TreeNode s:getTree(small)){
TreeNode root=new TreeNode(list.get(i));//初始化根节点一定要写在这里
root.right=b;
root.left=s;
result.add(root);
}
}
}
return result;
}
public List<TreeNode> generateTrees(int n) {
List<Integer> list=new ArrayList<>();
for(int i=1;i<=n;i++){
list.add(i);
}
return getTree(list);
}
}
3)其他解法
class Solution {
public List<TreeNode> generateTrees(int n) {
if (n == 0) {
return new LinkedList<TreeNode>();
}
return generateTrees(1, n);
}
public List<TreeNode> generateTrees(int start, int end) {
List<TreeNode> allTrees = new LinkedList<TreeNode>();
if (start > end) {
allTrees.add(null);
return allTrees;
}
// 枚举可行根节点
for (int i = start; i <= end; i++) {
// 获得所有可行的左子树集合
List<TreeNode> leftTrees = generateTrees(start, i - 1);
// 获得所有可行的右子树集合
List<TreeNode> rightTrees = generateTrees(i + 1, end);
// 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
for (TreeNode left : leftTrees) {
for (TreeNode right : rightTrees) {
TreeNode currTree = new TreeNode(i);
currTree.left = left;
currTree.right = right;
allTrees.add(currTree);
}
}
}
return allTrees;
}
}
作者:LeetCode-Solution
链接:link
来源:力扣(LeetCode)
4)自己的优化代码
c++
class Solution {
public List<TreeNode> getTree(List<Integer> list){
List<TreeNode> result=new ArrayList<>();
if(list.size()==1&&list.get(0)==0){
TreeNode t=null;
result.add(t);
return result;
}
else if(list.size()==1){
result.add(new TreeNode(list.get(0)));
return result;
}
for(int i=0;i<list.size();i++){
List<Integer> small=new ArrayList<>();
List<Integer> big=new ArrayList<>();
for(Integer I:list){
if(I>list.get(i))big.add(I);
else if(I<list.get(i))small.add(I);
}
if(small.size()==0)small.add(0);
if(big.size()==0)big.add(0);
for(TreeNode b:getTree(big)){
for(TreeNode s:getTree(small)){
TreeNode root=new TreeNode(list.get(i));//初始化根节点一定要写在这里
root.right=b;
root.left=s;
result.add(root);
}
}
}
return result;
}
public List<TreeNode> generateTrees(int n) {
List<Integer> list=new ArrayList<>();
for(int i=1;i<=n;i++){
list.add(i);
}
return getTree(list);
}
}
5)学到的东西
分治思想:分成一个个小部分,之后可以通过用几个容器存放这些小部分,如该本题中我用了small和big存放分出来的小部分
当该变量需要被多次改变时,注意变量初始化的位置