[NineChap 1.2] Permutation

转载:http://www.shuatiblog.com/blog/2014/06/12/NineChap-Permutation/

COMMENTS

First Word

Permutation questions provide you with a list of items, and you build, validate and return a combination of these items. The standard solution is to sort the input first, and add items 1 by 1.

Do not try to solve the problems with anything other than the template given below, because otherwise the code is impossible to be bug-free.

Though the code is standard, many question are very difficult, and most of time duplication removal can be tough.

Template

public List<List<Integer>> subsets(int[] num) {
    List<List<Integer>> result = new ArrayList<List<Integer>>();
    if(num == null || num.length == 0) {
        return result;
    }
    Arrays.sort(num);  
    subsetsHelper(result, new ArrayList<Integer>(), num, 0);
    return result;
}

private void subsetsHelper(List<List<Integer>> result,
    List<Integer> list, int[] num, int pos) {
    result.add(new ArrayList<Integer>(list));
    for (int i = pos; i < num.length; i++) {
        list.add(num[i]);
        subsetsHelper(result, list, num, i + 1);
        list.remove(list.size() - 1);
    }
}

Note: 2nd last line “subsetsHelper(result, list, num, i + 1);”.

It’s easy to mistake it as “pos+1” instead of “i+1”, which will result in TLE.

Question list

  1. Subsets

  2. Permutations

  3. Subsets II

  4. Permutations II

Additional
  1. Combination Sum

  2. Combination Sum II

  3. Palindrome Partitioning

  4. Palindrome Partitioning II

  5. Restore IP Addresses

  6. Combinations

  7. Letter Combinations of a Phone Number

Code

Subsets – good example for practise (by applying the model)

public List<List<Integer>> subsets(int[] num) {
    List<List<Integer>> result = new ArrayList<List<Integer>>();
    if(num == null || num.length == 0) {
        return result;
    }
    Arrays.sort(num);
    helper(result, new LinkedList<Integer>(), num, 0);
    return result;
}

private void helper(List<List<Integer>> ans, List<Integer> path, int[] num, int position) {
    ans.add(new LinkedList<Integer>(path));
    for (int i = position; i < num.length; i ++) {
        path.add(num[i]);
        helper(ans, path, num, i + 1);
        path.remove(path.size() - 1);
    }
}

Permutations

public List<List<Integer>> permute(int[] num) {
    List<List<Integer>> ans = new LinkedList<List<Integer>>();
    if (num == null || num.length == 0) {
        return ans;
    }
    helper(ans, new LinkedList<Integer>(), num);
    return ans;
}

private void helper(List<List<Integer>> ans, List<Integer> path, int[] num){
    if (path.size() == num.length) {
        ans.add(new LinkedList<Integer>(path));
        return;
    }
    for (int i = 0; i < num.length; i ++) {
        if (!path.contains(num[i])) {
            path.add(num[i]);
            helper(ans, path, num);
            path.remove(path.size() - 1);
        }
    }
}

Subsets II – good example for practise

We only care how many times we use the duplicate number, we care not the order. So, only 3 lines of code is added based on previous solution.

public List<List<Integer>> subsetsWithDup(int[] num) {
    List<List<Integer>> result = new ArrayList<List<Integer>>();
    if(num == null || num.length == 0) {
        return result;
    }
    Arrays.sort(num);
    helper(result, new LinkedList<Integer>(), num, 0);
    return result;
}

private void helper(List<List<Integer>> ans, List<Integer> path, int[] num, int position) {
    ans.add(new LinkedList<Integer>(path));
    for (int i = position; i < num.length; i ++) {
        if (i > position && num[i - 1] == num[i]) {
            // if duplicate, only append num[position]
            continue;
        }
        path.add(num[i]);
        helper(ans, path, num, i + 1);
        path.remove(path.size() - 1);
    }
}

Permutations II

public List<List<Integer>> permuteUnique(int[] num) {
    List<List<Integer>> ans = new LinkedList<List<Integer>>();
    if (num == null || num.length == 0) {
        return ans;
    }
    Arrays.sort(num);
    helper(ans, new LinkedList<Integer>(), new int[num.length], num);
    return ans;
}

private void helper(List<List<Integer>> ans, List<Integer> path, int[] visited, int[] num){
    if (path.size() == num.length) {
        ans.add(new LinkedList<Integer>(path));
        return;
    }
    for (int i = 0; i < num.length; i ++) {
        if (visited[i] == 1) {
            continue;
        }
        if (i > 0 && visited[i-1] == 0 && num[i - 1] == num[i]) {
            continue;
        }
        visited[i] = 1;
        path.add(num[i]);
        helper(ans, path, visited, num);
        visited[i] = 0;
        path.remove(path.size() - 1);
    }
}

Combination Sum

public ArrayList<ArrayList<Integer>> combinationSum(int[] candidates, int target) {
    ArrayList<ArrayList<Integer>> ans = new ArrayList<ArrayList<Integer>>();
    Arrays.sort(candidates);
    helper(ans, new ArrayList<Integer>(), candidates, 0, target);
    return ans;
}

private void helper(ArrayList<ArrayList<Integer>> ans, ArrayList<Integer> path, 
                    int[] nums, int pos, int target) {
    if (target < 0) {
        return;
    } else if (target == 0) {
        ans.add(new ArrayList<Integer>(path));
        return;
    }
    for (int i = pos; i < nums.length; i ++) {
        path.add(nums[i]);
        helper(ans, path, nums, i, target - nums[i]);
        path.remove(path.size() - 1);
    }
}

Combination Sum II

public ArrayList<ArrayList<Integer>> combinationSum2(int[] candidates, int target) {
    ArrayList<ArrayList<Integer>> ans = new ArrayList<ArrayList<Integer>>();
    Arrays.sort(candidates);
    helper(ans, new ArrayList<Integer>(), candidates, 0, target);
    return ans;
}

private void helper(ArrayList<ArrayList<Integer>> ans, ArrayList<Integer> path, 
                    int[] nums, int pos, int target) {
    if (target < 0) {
        return;
    } else if (target == 0) {
        ans.add(new ArrayList<Integer>(path));
        return;
    }
    for (int i = pos; i < nums.length; i ++) {
        if (i > pos && nums[i-1] == nums[i]) {
            continue;
        }
        path.add(nums[i]);
        helper(ans, path, nums, i + 1, target - nums[i]);
        path.remove(path.size() - 1);
    }
}

Palindrome Partitioning

Naive approach can AC:

public ArrayList<ArrayList<String>> partition(String s) {
    ArrayList<ArrayList<String>> ans = new ArrayList<ArrayList<String>>();
    if (s == null || s.length() == 0) {
        return ans;
    }
    helper(ans, new ArrayList<String>(), s, 0);
    return ans;
}

private void helper(ArrayList<ArrayList<String>> ans, ArrayList<String> path, String s, int pos) {
    if (pos == s.length()) {
        ans.add(new ArrayList<String>(path));
        return;
    }
    for (int i = pos + 1; i <= s.length(); i++) {
        String sub = s.substring(pos, i);
        if (!isPlm(sub)) {
            continue;
        }
        path.add(sub);
        helper(ans, path, s, i);
        path.remove(path.size() - 1);
    }
}

private boolean isPlm(String str) {
    int left = 0, right = str.length() - 1;
    while (left < right) {
        if (str.charAt(left) != str.charAt(right)) 
            return false;
        left++;
        right--;
    }
    return true;
}

Use DP to optimize the process of palindrome validation.

// palindrome validation optimized with DP
public ArrayList<ArrayList<String>> partition(String s) {
    ArrayList<ArrayList<String>> ans = new ArrayList<ArrayList<String>>();
    if (s == null || s.length() == 0) {
        return ans;
    }
    helper(ans, new ArrayList<String>(), s, 0, palindromeMap(s));
    return ans;
}

private void helper(ArrayList<ArrayList<String>> ans, 
ArrayList<String> path, String s, int pos, boolean[][] palinMap) {
    if (pos == s.length()) {
        ans.add(new ArrayList<String>(path));
        return;
    }
    for (int i = pos; i < s.length(); i++) {
        if (!palinMap[i][pos]) {
            continue;
        }
        path.add(s.substring(pos, i + 1));
        helper(ans, path, s, i + 1, palinMap);
        path.remove(path.size() - 1);
    }
}

private boolean[][] palindromeMap(String s) {
    int len = s.length();
    boolean[][] map = new boolean[len][len];
    char[] ss = s.toCharArray();
    for (int i = 0; i < len; i++) {
        for (int j = i; j >= 0; j--) {
            if (i == j) {
                map[i][j] = true;
            } else if (i - j == 1) {
                map[i][j] = ss[i] == ss[j];
            } else {
                map[i][j] = (ss[i] == ss[j]) & map[i - 1][j + 1];
            }
        }
    }
    return map;
}

Palindrome Partitioning II

Used above template and got TLE. Turns out, this is a pure DP question.

Skip for now.

Restore IP Addresses

public List<String> restoreIpAddresses(String s) {
    List<String> ans = new LinkedList<String>();
    if (s == null || s.length() == 0) {
        return ans;
    }
    helper(ans, s, "", 0, 0);
    return ans;
}

private void helper(List<String> ans, String s, String path, int pos, int count) {
    if (count == 4) {
        if (pos == s.length()) {
            ans.add(path.substring(1));
        }
        return;
    }
    for (int i = pos; i < s.length(); i++) {
        if (i - pos >= 3) {
            break;
        }
        if (!isValidNum(s.substring(pos, i + 1))) {
            continue;
        }
        String newPath = path + "." + s.substring(pos, i + 1);
        helper(ans, s, newPath, i + 1, count + 1);
    }
}

private boolean isValidNum(String str) {
    if (str.length() > 1 && str.charAt(0) == '0') {
        return false;
    }
    int num = Integer.parseInt(str);
    if (num < 0 || 255 < num) {
        return false;
    }
    return true;
}

Combinations

public List<List<Integer>> combine(int n, int k) {
    List<List<Integer>> ans = new LinkedList<List<Integer>>();
    if (n == 0 || k == 0 || n < k) {
        return ans;
    }
    helper(ans, new LinkedList<Integer>(), n, k, 1);
    return ans;
}

private void helper(List<List<Integer>> ans, List<Integer> path, int n, int k, int pos) {
    if (path.size() == k) {
        ans.add(new LinkedList<Integer>(path));
        return;
    }
    for (int i = pos; i <= n; i++) {
        path.add(i);
        helper(ans, path, n, k, i + 1);
        path.remove(path.size() - 1);
    }
}

Letter Combinations of a Phone Number

public List<String> letterCombinations(String digits) {
    List<String> ans = new LinkedList<String>();
    if (digits == null) {
        return ans;
    }
    String[] pad = new String[]{
        " ","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    helper(ans, "", pad, digits, 0);
    return ans;
}

private void helper(List<String> ans, String path, String[] pad, String digits, int pos) {
    if (path.length() == digits.length()) {
        ans.add(path);
        return;
    }
    String letters = pad[digits.charAt(pos) - '0'];
    for (int i = 0; i < letters.length(); i++) {
        path += letters.charAt(i) + "";
        helper(ans, path, pad, digits, pos + 1);
        path = path.substring(0, path.length() - 1);
    }
}

Conclusion

Remember the model! It applies to most search question.

   ninechap


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值