分治法:
最长公共前缀
合并 k 个排序链表:
二叉搜索树的生成
字符串的回文切割法
运算表达式增加括号
字符串的回文字符串返回
翻转游戏
累加数
单词缩写
最长公共前缀:
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例 1:
输入: [“flower”,“flow”,“flight”]
输出: “fl”
示例 2:
输入: [“dog”,“racecar”,“car”]
输出: “”
class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs.length==0||strs[0].length()==0)return "";
String result=this.divide(strs,0,strs.length-1);
return result;
}
public String divide(String []strs,int left,int right){
if(left==right) return strs[left];
int mid=(left+right)/2;
String a=divide(strs,left,mid);
String b=divide(strs,mid+1,right);
for(int i=0;ii&&b.charAt(i)==(a.charAt(i)))continue;
else return a.substring(0,i);
}
return a;
}
}
合并 k 个排序链表:
返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
解析:利用分治法,归并排序的模板
class Solution {
ListNode[] lists;
public ListNode mergeKLists(ListNode[] lists) {
this.lists=lists;
return solve(0,lists.length-1);
}
public ListNode solve(int left,int right){
if(left>right)return null;
if(left==right)return lists[left];
ListNode leftList=solve(left,(left+right)/2);
ListNode rightList=solve((left+right)/2+1,right);
return merge(leftList,rightList);
}
public ListNode merge(ListNode list1,ListNode list2){
ListNode dummy=new ListNode(0);
ListNode node=dummy;
while(list1!=null||list2!=null){
int num1=(list1!=null?list1.val:Integer.MAX_VALUE);
int num2=(list2!=null?list2.val:Integer.MAX_VALUE);
if(num1>num2){
node.next=list2;
node=list2;
list2=list2.next;
}
else{
node.next=list1;
node=list1;
list1=list1.next;
}
}
return dummy.next;
}
}
二叉搜索树生成
给定一个整数 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
解析:进阶版。有多少棵树。
思想仍然是上面的思想,只不过对于n个节点,中间每个节点都能作为根
所以for(i=1;i<=n;i++)表示每一个节点作为根的情况
其中对于节点J
而leftTrees代表1-(j-1)个节点分别作为根的时候的情况,leftTrees里一共有j-1个根
rightTreess代表(n-j)个节点作为根的时候的情况,rightTrees里一共有n-j个根
利用 for (TreeNode leftTree : leftTrees) {
for (TreeNode rightTree : rightTrees) 将其组合,得到结果
class Solution {
public List generateTrees(int n) {
List ans = new ArrayList();
if (n == 0) {
return ans;
}
return getAns(1, n);
}
private List getAns(int start, int end) {
List ans = new ArrayList();
//此时没有数字,将 null 加入结果中
if (start > end) {
ans.add(null);
return ans;
}
//只有一个数字,当前数字作为一棵树加入结果中
if (start == end) {
TreeNode tree = new TreeNode(start);
ans.add(tree);
return ans;
}
//尝试每个数字作为根节点
for (int i = start; i <= end; i++) {
//得到所有可能的左子树
List leftTrees = getAns(start, i - 1);
//得到所有可能的右子树
List rightTrees = getAns(i + 1, end);
//左子树右子树两两组合
for (TreeNode leftTree : leftTrees) {
for (TreeNode rightTree : rightTrees) {
TreeNode root = new TreeNode(i);
root.left = leftTree;
root.right = rightTree;
//加入到最终结果中
ans.add(root);
}
}
}
return ans;
}
}
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例:
输入: “aab”
输出:
[
[“aa”,“b”],
[“a”,“a”,“b”]
]
解析:首先利用冬天规划得到回文子串的(i,j),之后利用分治思想加递归。
class Solution {
public List> partition(String s) {
boolean[][] dp = new boolean[s.length()][s.length()];
int length = s.length();
for (int len = 1; len <= length; len++) {
for (int i = 0; i <= s.length() - len; i++) {
int j = i + len - 1;
dp[i][j] = s.charAt(i) == s.charAt(j) && (len < 3 || dp[i + 1][j - 1]);
}
}
return partitionHelper(s, 0, dp);
}
public List> partitionHelper(String str,int start ,boolean [][]dp){
if(start==str.length()){
List list = new ArrayList<>();
List> ans = new ArrayList<>();
ans.add(list);
return ans;
}
List> ans = new ArrayList<>();
for(int i=start;i right:partitionHelper(str,i+1,dp)){
right.add(0,left);
ans.add(right);
}
}
}
return ans;
}
}
运算表达式增加括号
给定一个含有数字和运算符的字符串,为表达式添加括号,改变其运算优先级以求出不同的结果。你需要给出所有可能的组合的结果。有效的运算符号包含 +, - 以及 * 。
示例 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
解析:分治法
class Solution {
public List diffWaysToCompute(String input) {
return getValue(input);
}
public List getValue(String input){
List list=new ArrayList<>();
if(!input.contains("-")&&!input.contains("+")&&!input.contains("*")){list.add(Integer.valueOf(input));return list;}
for(int i=0;i
字符串的回文字符串返回
给定一个字符串 s ,返回其通过重新排列组合后所有可能的回文字符串,并去除重复的组合。
如不能形成任何回文排列时,则返回一个空列表。
示例 1:
输入: “aabb”
输出: [“abba”, “baab”]
示例 2:
输入: “abc”
输出: []
public class Solution {
Set < String > set = new HashSet < > ();
public List < String > generatePalindromes(String s) {
int[] map = new int[128];
char[] st = new char[s.length() / 2];
if (!canPermutePalindrome(s, map))
return new ArrayList < > ();
char ch = 0;
int k = 0;
for (int i = 0; i < map.length; i++) {
if (map[i] % 2 == 1)
ch = (char) i;
for (int j = 0; j < map[i] / 2; j++) {
st[k++] = (char) i;
}
}
permute(st, 0, ch);
return new ArrayList < String > (set);
}
public boolean canPermutePalindrome(String s, int[] map) {
int count = 0;
for (int i = 0; i < s.length(); i++) {
map[s.charAt(i)]++;
if (map[s.charAt(i)] % 2 == 0)
count--;
else
count++;
}
return count <= 1;
}
public void swap(char[] s, int i, int j) {
char temp = s[i];
s[i] = s[j];
s[j] = temp;
}
void permute(char[] s, int l, char ch) {
if (l == s.length) {
set.add(new String(s) + (ch == 0 ? "" : ch) + new StringBuffer(new String(s)).reverse());
} else {
for (int i = l; i < s.length; i++) {
if (s[l] != s[i] || l == i) {
swap(s, l, i);
permute(s, l + 1, ch);
swap(s, l, i);
}
}
}
}
}
翻转游戏
累加数
单词缩写
翻转游戏:
你和朋友玩一个叫做「翻转游戏」的游戏,游戏规则:给定一个只有 + 和 - 的字符串。你和朋友轮流将 连续 的两个 “++” 反转成 “–”。 当一方无法进行有效的翻转时便意味着游戏结束,则另一方获胜。
请你写出一个函数来判定起始玩家是否存在必胜的方案。
示例:
输入: s = “++++”
输出: true
解析:记忆化搜索,也就是对每个搜索的状态进行保存
class Solution {
Map map=new HashMap<>();
public boolean canWin(String s) {
if(map.containsKey(s))return map.get(s);
for(int i=1;i
累加数
累加数是一个字符串,组成它的数字可以形成累加序列。
一个有效的累加序列必须至少包含 3 个数。除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和。
给定一个只包含数字 ‘0’-‘9’ 的字符串,编写一个算法来判断给定输入是否是累加数。
说明: 累加序列里的数不会以 0 开头,所以不会出现 1, 2, 03 或者 1, 02, 3 的情况。
示例 1:
输入: “112358”
输出: true
解释: 累加序列为: 1, 1, 2, 3, 5, 8 。1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, 3 + 5 = 8
示例 2:
输入: “199100199”
输出: true
解释: 累加序列为: 1, 99, 100, 199。1 + 99 = 100, 99 + 100 = 199
class Solution {
public boolean isAdditiveNumber(String num) {
if(num==null || num.length() < 3) return false;
for(int i = 1 ; i<=num.length()/2; i++){
//如果以0开头,则只能取0作为加数
if(num.charAt(0)=='0' && i>1) break;
String s1 = num.substring(0, i);
long num1 = Long.parseLong(s1);
for(int j = i+1 ; j<=num.length()-i ; j++){
//如果以0开头,则只能取0作为加数
if(num.charAt(i)=='0' && j>i+1) break;
String s2 = num.substring(i, j);
long num2 = Long.parseLong(s2);
//递归判断
if(isAdditiveNumber(num.substring(j), num1, num2)){
return true;
}
}
}
return false;
}
private boolean isAdditiveNumber(String num, long num1, long num2){
//如果剩余长度为0,说明之前都是AdditiveNumber,返回true
if(num.length()==0) return true;
long add = num1 + num2;
String adds = add + "";
//递归判断
return num.startsWith(adds) && isAdditiveNumber(num.substring(adds.length()), num2, add);
}
}
单词缩写:
请你写出一个能够举单词全部缩写的函数。
注意:输出的顺序并不重要。
示例:
输入: "word"
输出:
["word", "1ord", "w1rd", "wo1d", "wor1", "2rd", "w2d", "wo2", "1o1d", "1or1", "w1r1", "1o2", "2r1", "3d", "w3", "4"]
class Solution {
public List generateAbbreviations(String word) {
List list=new LinkedList();
list.add(word);
if(word.equals(""))return list;
list.add(""+word.length());
for(int i=0;i='0'&&str.charAt(0)<='9'))list.add(""+word1.length()+str);
if(!(str.charAt(0)>='a'&&str.charAt(0)<='z'))list.add(word1+str);
}
}
return list;
}