leetcode总结——分治

分治法:
最长公共前缀
合并 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
((2
3)-(45)) = -14
((2
(3-4))5) = -10
(2
((3-4)5)) = -10
(((2
3)-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;
	    }

你可能感兴趣的:(Leetcode1)