leetcode:查找

1.  word ladder

题目

Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:

  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the dictionary

For example,

Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]

As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.

Note:

  • Return 0 if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.

题解

 这道题是套用BFS同时也利用BFS能寻找最短路径的特性来解决问题 。所有的变化情况联系起来就是一棵树, 相当于从根结点start出发寻找特定的节点end。

 把每个单词作为一个node进行BFS。当取得当前字符串时,对他的每一位字符进行从a~z的替换,如果在字典里面,就入队,并将下层count++,并且为了避免环路,需把在字典里检测到的单词从字典里删除。这样对于当前字符串的每一位字符安装a~z替换后,在queue中的单词就作为下一层需要遍历的单词了。

 正因为BFS能够把一层所有可能性都遍历了,所以就保证了一旦找到一个单词equals(end),那么return的路径肯定是最短的。

 像给的例子 start = hit,end = cog,dict = [hot, dot, dog, lot, log]

 按照上述解题思路的走法就是:

  level = 1    hit   dict = [hot, dot, dog, lot, log]

         ait bit cit ... xit yit zit ,  hat hbt hct ... hot ... hxt hyt hzt ,  hia hib hic ... hix hiy hiz

  level = 2    hot  dict = [dot, dog, lot, log]

         aot bot cot dot ...  lot ... xot yot zot,hat hbt hct ... hxt hyt hzt,hoa hob hoc ... hox hoy hoz

  level = 3    dot lot  dict = [dog log]

         aot bot ... yot zot,dat dbt ...dyt dzt,doa dob ... dog .. doy doz,

         aot bot ... yot zot,lat lbt ... lyt lzt,loa lob ... log... loy loz

  level = 4   dog log dict = [] 

         aog bog cog

  level = 5   cog  dict = []

public int ladderLength(String start, String end, HashSet<String> dict) {
        if(start==null || end==null || start.length()==0 || end.length()==0 || start.length()!=end.length())  
        return 0; 
        
        LinkedList<String> wordQueue = new LinkedList<String>();
        int level = 1; //the start string already count for 1
        int curnum = 1;//the candidate num on current level
        int nextnum = 0;//counter for next level
        //一个单词变换一个字母后可能有多个符合条件的单词,即多个子节点
        
        wordQueue.add(start);
        
        while(!wordQueue.isEmpty()){
            //poll移除并返问队列头部的元素;
            //peek返回队列头部的元素; 
            String word = wordQueue.poll();
            curnum--;
            
            for(int i = 0; i < word.length(); i++){
                
                char[] wordunit = word.toCharArray();
                
                for(char j = 'a'; j <= 'z'; j++){
                    //字符串不可修改,转换成字符数组
                    wordunit[i] = j;
                    String temp = new String(wordunit);  
                    
                    if(temp.equals(end))
                        return level+1;
                    
                    if(dict.contains(temp)){
                        wordQueue.add(temp);
                        nextnum++;
                        dict.remove(temp);
                    }
                }
            }
            
            if(curnum == 0){
                curnum = nextnum;
                nextnum = 0;
                level++;
            }
            
        }
        
        return 0;
    }
View Code

 

2. N queens

题目:

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.

For example,
There exist two distinct solutions to the 4-queens puzzle:

[
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
 ]

题解:
经典的DFS递归回溯解法,大体思路就是对每一行,按每一列挨个去试,试到了就保存结果没试到就回溯。
难点大概就是用1个一维数组存皇后所在的坐标值。对于一个棋盘来说,每个点都有横纵坐标,用横纵坐标可以表示一个点。
而这道题巧就巧在,每一行只能有一个皇后,也就是说,对于一行只能有一个纵坐标值,所以用1维数组能提前帮助解决皇后不能在同一行的问题。
那么用一维数组表示的话,方法是:一维数组的下标表示横坐标(哪一行),而数组的值表示纵坐标(哪一列)

例如:对于一个4皇后问题,声明一个长度为4的数组(因为行数为4)。
A[] = [1,0,2,3]表达含义是:
当前4个皇后所在坐标点为:[[0,1],[1,0],[2,2],[3,3]](被我标蓝的正好是数组的下标,标粉的正好是数组的值)
相当于:A[0] = 1, A[1] = 0, A[2] = 2, A[3] = 3

这样以来,皇后所在的坐标值就能用一维数组表示了。
而正是这个一维数组,在回溯找结果的时候不需要进行remove重置操作了,因为回溯的话正好就回到上一行了,就可以再重新找下一个合法列坐标了。

因为是按照每一行去搜索的,当行坐标值等于行数时,说明棋盘上所有行都放好皇后了,这时就把有皇后的位置标为Q,没有的地方标为0。
按照上面讲的那个一维数组,我们就可以遍历整个棋盘,当坐标为(row,columnVal[row])的时候,就说明这是皇后的位置,标Q就行了。

public ArrayList<String[]> solveNQueens(int n) {
        ArrayList<String[]> res = new ArrayList<String[]>();
        if(n<=0)
            return res;
            
        int [] columnVal = new int[n];
        
        DFS_helper(n,res,0,columnVal);
        return res;
    }
    
    
    public void DFS_helper(int nQueens, ArrayList<String[]> res, int row, int[] columnVal){
        //row是当前测试的行号,row=nQueens时测试完毕
       if(row == nQueens){
            String[] unit = new String[nQueens];
            for(int i = 0; i < nQueens; i++){
                StringBuilder s = new StringBuilder();
                for(int j = 0; j < nQueens; j++){
                    if(j == columnVal[i])
                        s.append("Q");
                    else
                        s.append(".");
                }
                
                //将StringBuilder转换为String
                unit[i] = s.toString();
            }     
            res.add(unit);
            
        }else{
            for(int i = 0; i < nQueens; i++){
                
                //columnVal[] 存放位置,即第row行,第i列
                columnVal[row] = i;
                
                if(isValid(row,columnVal))
                    DFS_helper(nQueens, res, row+1, columnVal);
            }
        }
    }
    
    //判断新加入的row行那个queen是否和之前所有行的queen冲突
    public boolean isValid(int row, int [] columnVal){
        for(int i = 0; i < row; i++){
            //因为采用一维数组存储,所以不需要比较是否在同一行(每行只有一个元素)
            if(columnVal[row] == columnVal[i] //在同一列
               ||Math.abs(columnVal[row]-columnVal[i]) == row-i)   //在对角线
               return false;
        }
        return true;
    }
View Code

3.  word search

题目 :

Given a 2D board and a word, find if the word exists in the grid.

The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.

For example,

Given board =

[
  ["ABCE"],
  ["SFCS"],
  ["ADEE"]
]

word = "ABCCED" , -> returns true ,

word = "SEE" , -> returns true ,

word = "ABCB" , -> returns false .

题解 :

这道题分析看,就是一个词,在一行出现也是true,一列出现也是true,一行往下拐弯也是true,一行往上拐弯也是true,一列往左拐弯也是true,一列往右拐弯也是true。所以是要考虑到所有可能性,基本思路是使用DFS来对一个起点字母上下左右搜索,看是不是含有给定的Word。还要维护一个visited数组,表示从当前这个元素是否已经被访问过了,过了这一轮visited要回false,因为对于下一个元素,当前这个元素也应该是可以被访问的。

public class Solution {  
    private int row;  
    private int col;  
    public boolean exist(char[][] board, String word) {  
        row = board.length;  
        col = board[0].length;  
        boolean[][] visited = new boolean[row][col];  
        for (int i = 0; i < row; i++) {  
            for (int j = 0; j < col; j++) {  
                if (dfs(board, word, 0, i, j, visited))  
                    return true;  
            }  
        }  
        return false;  
    }  
  
    private boolean dfs(char[][] board, String word, int index, int rowindex,  
            int colindex, boolean[][] visited) {  
            
        //index是已经匹配的字母长度
        if (index == word.length())  
            return true;  
        
        if (rowindex < 0 || colindex < 0 || rowindex >= row || colindex >= col)  
            return false;  
        
        //visited记录该点是否已经被访问过
        if (visited[rowindex][colindex])  
            return false;  
        
        //该处字母是否匹配要查找的word
        if (board[rowindex][colindex] != word.charAt(index))  
            return false;  
        
        visited[rowindex][colindex] = true;  
        
        //四个方向至少有一个找到即可
        boolean res = dfs(board, word, index + 1, rowindex - 1, colindex,  
                visited)  
                || dfs(board, word, index + 1, rowindex + 1, colindex, visited)  
                || dfs(board, word, index + 1, rowindex, colindex + 1, visited)  
                || dfs(board, word, index + 1, rowindex, colindex - 1, visited);  
            
        //这轮完了。该点对于下一轮还是可以访问的
        visited[rowindex][colindex] = false;  
        
        return res;  
View Code

4.search for a rangr

题目:

Given a sorted array of integers, find the starting and ending position of a given target value.

Your algorithm's runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].

从题目中获取到关键字:sorted array ,find...position, a given target value, O(logn). 

这些关键字都在提醒我们这道题的思路应该是二分查找法。 

public class Solution {  
      
    public int searchStart(int[] A, int target) {  
        int start = 0, end = A.length - 1, result = -1, mid = 0;  
        while (start + 1 < end) {  
            mid = start + (end - start) / 2;  
            if(A[mid] > target) {  
                end = mid - 1;  
            } else if (A[mid] < target) {  
                start = mid + 1;  
            } else {  
                if(A[mid - 1] < target)  {  
                    return mid;  
                } else {  
                //此时mid, mid-1处的值都是target,mid-1之前也有可能是;
                //通过end=mid,让其从左边向mid逼近,找到最左的target
                    end = mid;   
                }  
            }  
        }  
        if (A[start] == target) return start;  
        else if (A[end] == target) return end;  
        else return -1;  
    }  
      
    public int searchEnd(int[] A, int target) {  
        int start = 0, end = A.length - 1, result = -1, mid = 0;  
        while (start + 1 < end) {  
            mid = start + (end - start) / 2;  
            if(A[mid] > target) {  
                end = mid - 1;  
            } else if (A[mid] < target) {  
                start = mid + 1;  
            } else {  
                if(A[mid + 1] > target)  {  
                    return mid;  
                } else {  
                    start = mid;  
                }  
            }  
        }  
        if (A[end] == target) return end;  
        else if (A[start] == target) return start;  
        else return -1;          
    }  
      
    public int[] searchRange(int[] A, int target) {  
        int [] result = new int[2];  
        result[0] = searchStart(A, target);  
        result[1] = searchEnd(A, target);  
        return result;  
    }  
}  
View Code

 

5. Combination sum 

题目:

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]

题解

还是老问题,用DFS找解决方案,不同点是,这道题: The same repeated number may be chosen from Cunlimited number of times.

所以,每次跳进递归不用都往后挪一个,还可以利用当前的元素尝试。

同时,这道题还要判断重复解。

 1.       if(i>0 && candidates[i] == candidates[i-1])//deal with dupicate
                 continue; 

 2.       if(!res.contains(item)) 
                res.add(new ArrayList<Integer>(item));   

这两个方法解决。 

public ArrayList<ArrayList<Integer>> combinationSum(int[] candidates, int target) {  
        ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();  
        ArrayList<Integer> item = new ArrayList<Integer>();
        if(candidates == null || candidates.length==0)  
            return res; 
            
        Arrays.sort(candidates);  
        helper(candidates,target, 0, item ,res);  
        return res;  
    }  
    
    
    //res放置最后结果,target控制“层级”,通过修改target,不断向下一层搜索
    private void helper(int[] candidates, int target, int start, ArrayList<Integer> item,   
    ArrayList<ArrayList<Integer>> res){ 
    
    
        // 搜索的退出条件
        if(target<0)  
            return;  
        if(target==0){  
            res.add(new ArrayList<Integer>(item));  
            return;  
        }
        
        
        for(int i=start;i<candidates.length;i++){  
            if(i>0 && candidates[i] == candidates[i-1])//deal with dupicate
                continue;  
            item.add(candidates[i]);
            
            int newtarget = target - candidates[i];
            helper(candidates,newtarget,i,item,res);//之所以不传i+1的原因是:
                                                    //The same repeated number may be 
                                                    //chosen from C unlimited number of times.
            item.remove(item.size()-1);  
        }  
    }
View Code

 

6.  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.

 对数字进行解析,相当于遍历一棵树,使用DFS

public List<String> letterCombinations(String digits) {
    HashMap<Integer, String> map = new HashMap<Integer, String>();
    map.put(2, "abc");
    map.put(3, "def");
    map.put(4, "ghi");
    map.put(5, "jkl");
    map.put(6, "mno");
    map.put(7, "pqrs");
    map.put(8, "tuv");
    map.put(9, "wxyz");
    map.put(0, "");
 
    ArrayList<String> result = new ArrayList<String>();
 
    if(digits == null || digits.length() == 0)
        return result;
 
    ArrayList<Character> temp = new ArrayList<Character>();
    getString(digits, temp, result, map);
 
    return result;
}
 
public void getString(String digits, ArrayList<Character> temp, ArrayList<String> result,  HashMap<Integer, String> map){
    if(digits.length() == 0){
        char[] arr = new char[temp.size()];
        for(int i=0; i<temp.size(); i++){
            arr[i] = temp.get(i);
        }
        result.add(String.valueOf(arr));
        return;
    }
    
    /*str=str.substring(int beginIndex);
    截取掉str从首字母起 长度为beginIndex的字符串,将剩余字符串赋值给str;

    str=str.substring(int beginIndex,int endIndex);
    截取str中从  下标beginIndex开始至endIndex-1结束时的字符串,并将其赋值给str;

    */
    
    Integer curr = Integer.valueOf(digits.substring(0,1));
    String letters = map.get(curr);
    for(int i=0; i<letters.length(); i++){
        
        temp.add(letters.charAt(i));
        
        getString(digits.substring(1), temp, result, map);
        
        temp.remove(temp.size()-1);
    }
}
View Code

7. Generate Parentheses leetcode java

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

For example, given n = 3, a solution set is:

"((()))", "(()())", "(())()", "()(())", "()()()"

DFS递归解决

给定的n为括号对,所以就是有n个左括号和n个右括号的组合。

按顺序尝试知道左右括号都尝试完了就可以算作一个解。

注意,左括号的数不能大于右括号,要不然那就意味着先尝试了右括号而没有左括号,类似“)(” 这种解是不合法的。

public ArrayList<String> generateParenthesis(int n) {  
        ArrayList<String> res = new ArrayList<String>();
        String item = new String();
        
        if (n<=0)
            return res;  
            
        dfs(res,item,n,n);  
        return res;  
    }  
      
      
     // item保存上一步的临时结果,res最终结果; leftt,right指示搜索层级变化
    public void dfs(ArrayList<String> res, String item, int left, int right){ 
        if(left > right)//deal wiith ")("
            return;
            
        if (left == 0 && right == 0){  
            res.add(new String(item));  
            return;  
        }
        
        if (left>0) 
            dfs(res,item+'(',left-1,right);  
        if (right>0) 
            dfs(res,item+')',left,right-1);  
    }
View Code
原文地址:https://www.cnblogs.com/zxqstrong/p/5363833.html