AdSense

Showing posts with label Backtracking. Show all posts
Showing posts with label Backtracking. Show all posts

Tuesday, April 7, 2015

[An overflow post] Longest valid subsequence

Given a string s, and a function isValid(String str), write a function to check the longest subsequence in s that is valid. For example, a subsequence in "whreat" can be "rat", "eat", "what" or "wheat". Please don't speculate the implementation of isValid(String str) function. 


I was asked this question yesterday. It bothered some much that the person who asked me this question and I could not agree on the solution. Plus I had a rough day&night last night, so I decide to break my rule to write this overflow post (256).

At first I thought it should be a DP problem, however, since we cannot assume anything about the isValid function, we can not break down the problem to smaller problem, i.e., "wh" is true will not indicate "what" is also true. So the only bloody brutal solution I can think of is backtracking.


public class LongestValidSubSequence {
 private static boolean isValid(String str){
  if(str.equals("what") || str.equals("wheat") || str.equals("eat") || str.equals("rat"))
   return true;
  return false;
 }
 static String max = "";
 public static String longestValidSubsequence(String str){
  getSubsequence(str, new StringBuilder(), 0);
  return max;
 }
 
 private static void getSubsequence(String str, StringBuilder sb, int start){
  if(isValid(sb.toString())){
   String tmp = sb.toString();
   if(max.length() < tmp.length()){
    max = tmp;
   }
  }
  for(int i = start; i < str.length(); i++){
   sb.append(str.charAt(i));
   getSubsequence(str, sb, i + 1);
   sb.deleteCharAt(sb.length() - 1);
  }
 }
 public static void main(String[] args) {
  String s = "whreat";
  System.out.println(longestValidSubsequence(s));

 }

}

Sunday, March 22, 2015

Largest rectangle of words


Given a dictionary of millions of words, give an algorithm to find the largest possible rectangle of letters such that every row forms a word (reading left to right) and every column forms a word (reading top to bottom). 

This is a very interesting problem. The book didn't give us a very clear solution. However, the approach is correct. First, group the words in the sets, the largest rectangle it can form must come the longest words, if they can form a rectangle. If they cannot, iteratively find all rectangles and compare it with the current maximum one.

To find the rectangle, I found a solution online mentioned using backtracking, however, I couldn't figure out that solution. I have an open question here, feel free to answer it if you know.

My solution is a generalized solution from my previous post, it is also a backtracking solution, but more like a bloody brutal one. I still use a trie to store all words in the columns. Each time I add a string into a row, check if all substrings formed by the columns can be found in the trie, if any of them cannot, return false. I also use a previous list to store all the previous substrings formed by the columns. This list will also be used to check if there are duplicates in rows and columns if the input set for rows and columns are the same.



As you see the code, it is very expensive and tedious. Finding the rectangle will take O(mn) where m is the rows of the rectangle and n is the columns of the rectangle. Group the words will take O(millions) given the problem set that there are millions of words. And iteratively find all possible rectangles will take O(millions * millions * m * n)... Don't want to even think of it.

I didn't test the code, so it may have some errors / bugs.



import java.util.*;
public class MakeRectangle {
 
 public List largestRectangle(Set dicts){
  if(dicts == null || dicts.size() == 0)
   return null;
  int L = getMax(dicts);
  List rst = new ArrayList ();
  List max = null;
  int maxArea = 0;
  for(int r = L; r >= 1; r--){
   for(int c = L; c >= 1; c--){
    Set rows = findWords(dicts, r);
    if(r == c)
     rst = rectangle(rows, r, rows, c);
    else{
     Set cols = findWords(dicts, c);
     rst = rectangle(rows, r, cols, c);
    }
    if(rst != null){
     //if the longest words can form a rectangle
     //it is guaranteed to be the largest one, return the rst
     if(r == L && c == L)
      return rst;
     //otherwise we wouldn't know which one has the largest area 
     //until we find all valid area
     int currArea = rst.size() * rst.get(0).length();
     if(max == null || maxArea < currArea){
      max = new ArrayList (rst);
      maxArea = currArea;
     }
    }
   }
  }
  return rst;
 }
 private int getMax(Set dicts){
  int length = 0;
  for(String s : dicts)
   length = Math.max(length, s.length());
  return length;
 }
 private Set findWords(Set dicts, int length){
  Set rst = new HashSet ();
  for(String s : dicts){
   if(s.length() == length)
    rst.add(s);
  }
  return rst;
 }
 //m: length of each word in cols
 //n: length of each word in rows
 public List rectangle(Set rows, int n, Set cols, int m){
  //since we need to build a rectangle, if number of words in rows 
  //is smaller than the length of the words in cols, then we will not have 
  //have enough words to build the rectangle, return null
  if(rows.size() < m || cols.size() < n)
   return null;
  List matrix = new ArrayList (m);
  Trie columns = new Trie();
  columns.add(cols);
  List previous = new ArrayList (n);
  for(int i = 0; i < n; i++)
   previous.add("");
  if(build(rows, columns, matrix, 0, previous, m))
   return matrix;
  return null;
 }
 private boolean build(Set rows, Trie columns, List matrix, int row, List previous, int m){
  if(row == m){
   //for the condition where rows and columns are from the same set, we need to avoid duplicates in rows and cols)
   if(previous.get(0).length() == m){
    for(String s : previous){
     if(matrix.contains(s))
      return false;
    }
   }
   return true;
  }
  for(String s : rows){
   if(matrix.contains(s))
    continue;
   boolean valid = true;
   int indexS = 0;
   int indexL = 0;
   while(indexS < s.length() && indexL < previous.size() && valid){
    String tmp = previous.get(indexL++) + s.charAt(indexS++);
    if(!columns.contains(tmp)){
     valid = false;
     break;
    }
   }
   if(!valid)
    continue;
   matrix.add(s);
   indexS = 0;
   indexL = 0;
   while(indexS < s.length() && indexL < previous.size()){
    previous.set(indexL, previous.get(indexL) + s.charAt(indexS));
    indexL++;
    indexS++;
   }
   if(build(rows, columns, matrix, row + 1, previous, m))
    return true;
   matrix.remove(matrix.size() - 1);
   indexL = 0;
   while(indexL < previous.size()){
    String tmp = previous.get(indexL);
    previous.set(indexL, tmp.substring(0, tmp.length() - 1));
   }
  }
  return false;
 }
 
}
import java.util.*;
public class Trie {
 protected final Map children;
 protected String value;
 protected boolean isWord = false;
 private Trie(String value){
  this.value = value;
  children = new HashMap();
 }
 public Trie(){
  this("");
 }
 
 public void add(String word){
  if(word == null || word.length() == 0){
   System.out.println("Cannot add null or empty string!");
   return;
  }
  Trie node = this;
  for(char c : word.toCharArray()){
   if(!node.children.containsKey(c)){
    node.put(c);
   }
   node = node.children.get(c);
  }
  isWord = true;
 }
 private void put(char c){
  children.put(c, new Trie(this.value + c));
 }
 public void add(Collection dict){
  for(String word : dict)
   add(word);
 }
 public boolean contains(String s){
  Trie node = this;
  for(char c : s.toCharArray()){
   if(!node.children.containsKey(c))
    return false;
   node = node.children.get(c);
  }
  return node.value.equals(s);
 }
 
}

Friday, January 9, 2015

Letter Combinations of a Phone Number

Given a digit string, return all possible letter combinations that the number could represent.
A mapping of digit to letters (just like on the telephone buttons) is given below.
Input:Digit string "23"
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
Note:
Although the above answer is in lexicographical order, your answer could be in any order you want.
Backtracking problem. Use a map <Integer, char[] > (or list) to store the mapping between numbers and letters. Starts from 0, every time we add one letter to the StringBuilder, its length will increment by 1. So in each recursion, we start the loop at the length of the string builder, which points to the next number in string digits whose mapping is to be added.



public List letterCombinations(String digits) {
        if (digits == null)
            throw new NullPointerException("Null string!");
        List rst = new ArrayList ();
        Map map = new HashMap();
        map.put('0', new char[] {});
        map.put('1', new char[] {});
        map.put('2', new char[] { 'a', 'b', 'c' });
        map.put('3', new char[] { 'd', 'e', 'f' });
        map.put('4', new char[] { 'g', 'h', 'i' });
        map.put('5', new char[] { 'j', 'k', 'l' });
        map.put('6', new char[] { 'm', 'n', 'o' });
        map.put('7', new char[] { 'p', 'q', 'r', 's' });
        map.put('8', new char[] { 't', 'u', 'v'});
        map.put('9', new char[] { 'w', 'x', 'y', 'z' });
        getLetter(digits, map, rst, new StringBuilder ());
        return rst;
    }
    private void getLetter(String digits, Map map, List rst, StringBuilder sb) {
        if (sb.length() == digits.length()) {
            rst.add(sb.toString());
            return;
        }
        for (char c : map.get(digits.charAt(sb.length()))) {
            sb.append(c);
            getLetter(digits, map, rst, sb);
            sb.deleteCharAt(sb.length() - 1);
        }
    }

Thursday, January 8, 2015

Combination Sum I & II

Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T
The same repeated number may be chosen from C unlimited number of times.
Note:
  • All numbers (including target) will be positive integers.
  • Elements in a combination (a1a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
  • The solution set must not contain duplicate combinations.
For example, given candidate set 2,3,6,7 and target 7,
A solution set is:
[7]
[2, 2, 3] 

I was confused at first how to repeatedly use an element. Then I realized that it is just start point of the recursion is different: start from i if the element can be repeatedly used and from i + 1 if it cannot.

Btw, the reason to use "start" but not start from the beginning of the array each time is to get only one combination each time. For example, to remove (2, 3, 2) from the combinations.

Otherwise they are just normal backtracking. O(n!)

Combinations I

public List> combinationSum(int[] candidates, int target) {
        if (candidates == null)
            throw new NullPointerException("Null array!");
        List> rst = new ArrayList> ();
        if (candidates.length == 0)
            return rst;
        Arrays.sort(candidates);
        getCombinations(candidates, target, rst, new ArrayList (), 0);
        return rst;
    }
    private void getCombinations(int[] candidates, int target, List> rst, List combination, int start) {
        if (target < 0)
            return;
        if (target == 0) {
            rst.add(new ArrayList(combination));
            return;
        }
        for (int i = start; i < candidates.length; i++) {
            if (candidates[i] > target)
                break;
            if (i != start && candidates[i] == candidates[i - 1])
                continue;
            combination.add(candidates[i]);
            getCombinations(candidates, target - candidates[i], rst, combination, i);
            combination.remove(combination.size() - 1);
        }
    }

Combinations II


public List> combinationSum2(int[] num, int target) {
        if (num == null)
            throw new NullPointerException("Null array!");
        List> rst = new ArrayList> ();
        if (num.length == 0)
            return rst;
        Arrays.sort(num);
        getCombinations(num, target, rst, new ArrayList (), 0);
        return rst;
        
    }
    private void getCombinations(int[] num, int target, List> rst, List combination, int start) {
     if (target < 0)
            return;
        if (target == 0) {
            rst.add(new ArrayList(combination));
            return;
        }
        for (int i = start; i < num.length; i++) {
            if (num[i] > target)
                break;
            if (i != start && num[i] == num[i - 1])
                continue;
            combination.add(num[i]);
            getCombinations(num, target - num[i], rst, combination, i + 1);
            combination.remove(combination.size() - 1);
        }
    }

Thursday, January 1, 2015

Sudoku Solver

Write a program to solve a Sudoku puzzle by filling the empty cells.
Empty cells are indicated by the character '.'.
You may assume that there will be only one unique solution.
A sudoku puzzle...
...and its solution numbers marked in red.
First, if you are interested in the rule, see here.

So, a method to check if the added number is valid is necessary. A hashset is used. Basically, check the entire row, the column and the sub-box where the number is at and see if the same number has already added, if it has, return false. Note the indices of the first element in the sub-box is calculated by row / 3 * 3  and col / 3 * 3. For example, row = 4, col = 5, we get the indices x = 3 and y = 3.

The main method is a boolean method. The game is solved by recursion. That is, when we add a valid number, we recursively check the next number we can add to the board until we find a solution. If a number added is not valid, we remove the number and add the next one.

That is, yeah, of course you love it, the backtracking!


public class Solution {
    public void solveSudoku(char[][] board) {
        if (!canBeSolved(board))
            System.out.println("Cannot be solved!");
    }
    private boolean canBeSolved (char[][] board) {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] != '.')
                    continue;
                for (int k = 1; k <= 9; k++) {
                    board[i][j] = (char) (k + '0');
                    if (isValid(board, i, j) && canBeSolved(board))
                        return true;
                    //return to '.' for next recursion
                    board[i][j] = '.';
                }
                
                return false;
            }
        }
        //go through the whole board
        return true;
    }
    private boolean isValid(char[][] board, int row, int col) {
        HashSet hs = new HashSet ();
        //the column
        for (int j = 0; j < board[0].length; j++) {
            if(hs.contains(board[row][j]))
                return false;
            //only add numbers
            if (board[row][j] != '.')
                hs.add(board[row][j]);
        }
        //the row
        hs.clear();
        for (int i = 0; i < board.length; i++) {
            if (hs.contains(board[i][col]))
                return false;
            if (board[i][col] != '.')
                hs.add(board[i][col]);
        }
        //the sub-box
        hs.clear();
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                int x = row / 3 * 3 + i;
                int y = col / 3 * 3 + j;
                if (hs.contains(board[x][y]))
                    return false;
                if (board[x][y] != '.')
                    hs.add(board[x][y]);
            }
        }
        return true;
    }
}

Tuesday, December 23, 2014

Find pythagorean triplets

I am doing this because of this post on Stackoverflow. The question is if there is an O(n) method to do this. Some replies are about using the same approach of  3Sum in LeetCode. I tried both the backtracking way and the 3Sum approach. Based on the code, they are both close to O(n^2) complexity. I tested both, honestly, even the 3Sum can be slightly faster because we trimmed of some iterations, no tremendous improvement.


import java.util.*;


public class PythagoreanTriple {
        //3Sum approach
 public ArrayList> findPythagorean(int[] nums) {
  ArrayList> rst = new ArrayList>();
  if (nums == null || nums.length == 0) {
   return rst;
  }
  Arrays.sort(nums);
  int[] square = new int[nums.length];
  for (int i = 0; i < nums.length; i++) {
   square[i] = nums[i] * nums[i]; 
  }
  for (int i = 0; i < nums.length - 2; i++) {
   if (i != 0 && nums[i] == nums[i - 1])
    continue;
   int left = i + 1;
   int right = nums.length - 1;
   while (left < right) {
    int sum = square[i] + square[left] - square[right];
    if (sum == 0) {
     ArrayList list = new ArrayList();
     list.add(nums[i]);
     list.add(nums[left]);
     list.add(nums[right]);
     rst.add(list);
     left++;
     right--;
     while (left < right && square[left] == square[left - 1]) {
      left++;
     }
     while (right > left && square[right] == square[right + 1]) {
      right--;
     }
    }
    else if (sum < 0) {
     right--;
    }
    else
     break;
   }
  }
  return rst;
 }
        //backtracking
 public ArrayList> findPythagorean2(int[] nums)
 {
  ArrayList> rst = new ArrayList>();
  if (nums == null || nums.length == 0)
   return rst;
  ArrayList tri = new ArrayList();
  Arrays.sort(nums);
  findTriangle(rst, tri, nums, 0);
  return rst;
 }
 private void findTriangle(ArrayList> rst, ArrayList tri, int[] nums, int start) {
  if (tri.size() == 3) {
   if (tri.get(0) * tri.get(0) + tri.get(1) * tri.get(1) == tri.get(2) * tri.get(2)) {
    rst.add(new ArrayList (tri));
   }
   return;
  }
  for (int i = start; i < nums.length; i++) {
   if (i != start && nums[i] == nums[i - 1])
    continue;
   tri.add(nums[i]);
   findTriangle(rst, tri, nums, i + 1);
   tri.remove(tri.size() - 1);
  }
 }
}

Tuesday, December 16, 2014

Palindrome Partitioning I & II

Given a string s, partition s such that every substring of the partition is a palindrome.
Return all possible palindrome partitioning of s.
For example, given s = "aab",
Return
  [
    ["aa","b"],
    ["a","a","b"]
  ]
The first problem is a typical backtracking problem. Start from index 0. We check each substring, and recursively check the next substring, until we reach the end of the string. If we successfully add all substrings into the partition list, we can add this partition to the rst list.

For example: s = "aab"

start = 0
check substring(0, 1) -> (1, 2) -> (2, 3) -> add
remove (2, 3)
(0, 1) -> (1, 3) not palindrome
(0, 2) -> (2, 3) -> add



public class PalindromePartition {
    public ArrayList> partition(String s) {
        if (s == null)
            throw new NullPointerException("Null string!");
        ArrayList> rst = new ArrayList> ();
        if (s.length() == 0)
            return rst;
        partitionString(s, rst, new ArrayList (), 0);
        return rst;
       
    }
    private void partitionString (String s, ArrayList> rst, ArrayList partition, int start) {
        if (start == s.length()) {
            rst.add(new ArrayList (partition));
            return;
        }
        for (int i = start + 1; i <= s.length(); i++) {
            String tmp = s.substring(start, i);
            if (!isPalindrome(tmp))
                continue;
            partition.add(tmp);
            partitionString(s, rst, partition, i);
            partition.remove(partition.size() - 1);
        }
    }
    private boolean isPalindrome(String s) {
        int start = 0;
        int end = s.length() - 1;
        while (start < end) {
            if (s.charAt(start) != s.charAt(end))
                return false;
            start++;
            end--;
        }
        return true;
    }
    
}


Given a string s, partition s such that every substring of the partition is a palindrome.
Return the minimum cuts needed for a palindrome partitioning of s.
For example, given s = "aab",
Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.

I am definitely not good at DP, especially when I need to it.. twice...

This problem is obviously a typical DP (when it comes to find the maximum or minimum, you probably want to start your approach of DP first).

I like to show things using examples, mainly because I am not at describing things.

s = "abbab"
        s.charAt(i)             0  1  2  3  4
        s                             a  b  b  a  b
possible places to cut: 0  1  2  3  4  5

So I define an array cut[s.length() + 1]. cut[i] is aimed to store the minimum cut needed for s.substring(0, i).
cut[0] =  0, obviously, empty string.
cut[1] = 0, because s.substring(0,1) is a palindrome (single character).
start from cut[2]:
    1. if s.substring(0, i) is a palindrome, cut[i] = 0;
    2. otherwise, if s.substring(start,i) (start = 1, ... i - 1) is a palindrome, cut[i] = cut[start] + 1;
return cut[s.length], which is cut[5] in this case.

The next part is, how to check if s.substring(start, end) is a palindrome. Of course we can do it iteratively, but is it more convenient if we draw a table of all palindrome substrings of s and just check the table every time?
Yep, that's pretty much the solution.

1. palindrome[i][i] is obviously a palindrome since it only contains one character.
2. palindrome[i][i + 1] is a palindrome if s.charAt(i) == s.charAt(j)
3. palindrome[i][j] is a palindrome if palindrome[i+1][j-1] && s.charAt(i) ==s.charAt(j)

start \ end   0   1   2   3    4
        0        T   F   F   T    F
        1             T   T   T    F
        2                  T    F   T
        3                        T   F
        4                             T




public class PalindromePartition {
    public int minCut(String s) {
        if (s == null || s.length() == 0)
            return 0;
        //**************************************
        // I write this single loop to check if the string itself is a plindrome, 
        //alternatively you can include it into the matrix or write a boolean checkPalindrome (s) method
        int startp = 0;
        int endp = s.length() - 1;
        while (startp < endp)
        {
         if(s.charAt(startp) != s.charAt(endp))
          break;
         startp++;
         endp--;
        }
        if (endp <= startp)
         return 0;
        //****************************************
        int[] cut = new int[s.length() + 1];
        boolean[][] palindromeMatrix = isPalindrome(s);
        cut[0] = 0;
        cut[1] = 0;
        for (int end = 2; end < cut.length; end++)
        {
            cut[end] = Integer.MAX_VALUE;
            if (palindromeMatrix[0][end - 1])
            {
                cut[end] = 0;
                continue;
            }
            for (int start = 1; start < end; start++)
            {
                if (!palindromeMatrix[start][end - 1])
                    continue;
                cut[end] = Math.min(cut[end], cut[start] + 1);
            }
        }
        return cut[s.length()];
    }
    private boolean[][] isPalindrome(String s)
    {
        boolean[][] palindromeMatrix = new boolean[s.length()][s.length()];
        for (int i = 0; i < s.length(); i++)
            palindromeMatrix[i][i] = true;
        for (int i = 0; i < s.length() - 1; i++)
            palindromeMatrix[i][i + 1] = (s.charAt(i) == s.charAt(i + 1));
        for (int length = 3; length < s.length(); length++)
        {
            for (int start = 0; start <= s.length() - length; start++)
                palindromeMatrix[start][start + length - 1] = (palindromeMatrix[start + 1][start + length - 2] && (s.charAt(start) == s.charAt(start + length - 1)));
        }
        return palindromeMatrix;
    }
}

Monday, December 15, 2014

N-Queens


A very tricky problem. I am not even a chess player, apparently it took me a while to first figure out what N-Queens game is.

Basic rule: "no two queens threaten each other. Thus, a solution requires that no two queens share the same row, column, or diagonal. "

The problem is solved by implementing back tracking algorithm. 

1. We start by placing the queen at each column. When we iterate for the next valid column, we assume the queen will be put in the next row, since no two queens share the same row. 
2. Recursively put the queen at different columns (and different rows of course), if a solution is found, we draw a chessboard and return the solution. 
3. Since we presume queens will be placed in different rows, we only need to check if two queens are
    1. in the same column 
    2. in the same main diagonal 
    3. in the same anti diagonal 
4. The chessboard is a string array with each element represents a row of places of the chessboard.

If the question is to output the number of solutions, set a public static int rst instead of the arraylist. 

public class NQueens {
    public ArrayList solveNQueens(int n) {
        ArrayList rst = new ArrayList();
        if (n <= 0 || n == 2 || n == 3)
            return rst;
        validQueens(rst, new ArrayList (), n);
        return rst;
        
    }
    private void validQueens(ArrayList rst, ArrayList queenCols, int n)
    {
        if (queenCols.size() == n)
        {
            String[] chessBoard = drawChessBoard(queenCols);
            rst.add(chessBoard);
            return;
        }
        
        for (int column = 0; column < n; column++)
        {
            if(!isValid(queenCols, column))
                continue;
            queenCols.add(column);
            validQueens(rst, queenCols, n);
            queenCols.remove(queenCols.size() - 1);
        }
    }
    private boolean isValid(ArrayList queenCols, int col)
    {
        //The queen will be placed in the next row, if the last row is i 
        //then this row will be i + 1, which equals the size of the arraylist 
        int row = queenCols.size();
        for (int i = 0; i < queenCols.size(); i++)
        {
            //same column
            if (col == queenCols.get(i))
                return false;
            //main diagonal 
            if (i - queenCols.get(i) == row - col)
                return false;//off diagonal
            if (i + queenCols.get(i) == row + col)
                return false;
        }
        return true;
    }
    private String[] drawChessBoard(ArrayList queenCols)
    {
        //chessboard is a string array, each element represents a row
   //cols has n element, the value of the i-th element represents the column at this row
   //where the queen should be put
        String[] chessBoard = new String[queenCols.size()];
        for (int row = 0; row < queenCols.size(); row++)
        {
            chessBoard[row] = "";
            for (int col = 0; col < queenCols.size(); col++)
            {
                if (col == queenCols.get(row))
                    chessBoard[row] += "Q";
                else
                    chessBoard[row] += ".";
            }
        }
        return chessBoard;
    }
    
}


N-Queens II


public class NQueens {
    public static int sum;
    public int totalNQueens(int n) {
        if (n == 0 || n == 2 || n == 3)
            return 0;
        sum = 0;
        validQueens(new ArrayList (), n);
        return sum;
    }
    private void validQueens(List queenCols, int n) {
        if (queenCols.size() == n) {
            sum++;
            return;
        }
        for (int col = 0; col < n; col++) {
            if(!isValid(queenCols, col))
                continue;
            queenCols.add(col);
            validQueens(queenCols, n);
            queenCols.remove(queenCols.size() - 1);
        }
    }
    private boolean isValid(List queenCols, int col) {
        int row = queenCols.size();
        for (int i = 0; i < queenCols.size(); i++) {
            if (col == queenCols.get(i))
                return false;
            if (i + queenCols.get(i) == row + col)
                return false;
            if (i - queenCols.get(i) == row - col)
                return false;
        }
        return true;
    }
}

Find possible triangle triplets

Woke up this morning I decided to find some problems that are not on LeetCode. Here is one from Careercup.

I used backtracking for this problem. However, it may not be the best solution since the complexity is O(n!).

"Given a array of positive integers, find all possible triangle triplets that can be formed from this array. 
eg: 9 8 10 7 
ans: 9 8 10, 9 8 7, 9 10 7, 7 8 10 
Note : array not sorted, there is no limit on the array length"

import java.util.ArrayList;
import java.util.Arrays;


public class PossibleTriangle {
 public ArrayList> possibleTriangle(int[] nums)
 {
  ArrayList> rst = new ArrayList>();
  if (nums == null || nums.length == 0)
   return rst;
  ArrayList triplets = new ArrayList();
  Arrays.sort(nums);
  getTriangle(rst, triplets, nums, 0);
  return rst;
 }
 private void getTriangle(ArrayList> rst, ArrayList triplets, 
   int[] nums, int start)
 {
  if (triplets.size() == 3 && triplets.get(0) + triplets.get(1) > triplets.get(2))
   rst.add(new ArrayList (triplets));
  for (int i = start; i < nums.length; i++)
  {
   if (i != start && nums[i] == nums[i - 1])
    continue;
   triplets.add(nums[i]);
   getTriangle(rst, triplets, nums, i + 1);
   triplets.remove(triplets.size() - 1);
  }
 }
 public void printList(ArrayList> rst)
 {
  for (int i = 0; i < rst.size(); i++)
   System.out.println(rst.get(i));
 }

}
public class TriangleTester {

 public static void main(String[] args) {
  // TODO Auto-generated method stub
  //int[] nums = {6, 6, 6, 6, 6, 6, 6, 6};
  int[] nums = {1, 2, 3, 6, 6, 7, 2, 9, 8};
  PossibleTriangle pt = new PossibleTriangle();
  ArrayList> rst = pt.possibleTriangle(nums);
  pt.printList(rst);

 }

}

Thursday, December 11, 2014

Subsets... II

"Given a collection of integers  S, return all possible subsets."
When it comes to problems like this, the question you should always ask yourself is: are there any duplicates? 
The answer is always yes! And here comes our Subsets II. 
It is defined as a backtracking problem. 
Basically, given a set S with duplicates [1,2,2]
add each element into the list, then remove it after add the list to the final and add the next one. 
To avoid duplicate lists, first condition is definitely num[i] != num[i - 1]. However, we still want to add i-th element if (i - 1)-th element is in the list as well as the condition where i-th element is the first element in the list. 
[1]  -> [1,2] -> [1,2,2] -> [1,2]  -> [1] -> [1, 2], duplicates, will not add -> [1] -> [] -> [2] -> [2,2] -> [2] ->[] -> [2], duplicates -> []. 


public class Solution {
    public ArrayList> subsetsWithDup(int[] num) {
        ArrayList> rst = new ArrayList>();
        if (num == null || num.length == 0)
            return rst;
        ArrayList list = new ArrayList();
        Arrays.sort(num);
        SetHelper(rst, list, num, 0);
        return rst;
    }
    private void SetHelper(ArrayList> rst, ArrayList list, int[] num, int start)
    {
        rst.add(new ArrayList(list));
        for (int i = start; i < num.length; i++)
        {
            if (i != start && num[i] == num[i - 1])
                continue;
            list.add(num[i]);
            SetHelper(rst, list, num, i + 1);
            list.remove(list.size() - 1);
        }
    }
}