Chapter one

1.strstr(字符串查找)

对于一个给定的 source 字符串和一个 target 字符串,你应该在 source 字符串中找出 target 字符串出现的第一个位置(从0开始)。如果不存在,则返回 -1

class Solution {
    /**
     * Returns a index to the first occurrence of target in source,
     * or -1  if target is not part of source.
     * @param source string to be scanned.
     * @param target string containing the sequence of characters to match.
     */
    public int strStr(String source, String target) {
        // write your code here
        if (source == null || target == null) {
            return -1;
        }
        for (int i = 0; i < source.length() - target.length() + 1; i++) {
            int j = 0;
            for (j = 0; j < target.length(); j++) {
                if (target.charAt(j) != source.charAt(i + j)) {
                    break;
                }
            }
            if (j == target.length()) {
                return i;
            }
        }
        return -1;
    }
}
View Code

思路:双重循环即可解决。注意第一重循环i的结束条件:source.length() - target.length() + 1。import java.lang.String

2.subsets(子集)

给定一个含不同整数(这些整数不重复)的集合,返回其所有的子集。子集中的元素排列必须是非降序的,解集必须不包含重复的子集。

class Solution {
    /**
     * @param S: A set of numbers.
     * @return: A list of lists. All valid subsets.
     */
    public ArrayList<ArrayList<Integer>> subsets(int[] nums) {
        // write your code here
        ArrayList<ArrayList<Integer>> results = new ArrayList<ArrayList<Integer>>();
        if (nums == null) {
            return results;
        }
        if (nums.length == 0) {
            results.add(new ArrayList<Integer>());
            return results;
        }
        Arrays.sort(nums);
        helper(results, new ArrayList<Integer>(), 0, nums);
        return results;
    }
    private void helper(ArrayList<ArrayList<Integer>> results,
                        ArrayList<Integer> subset,
                        int startIndex,
                        int[] nums) {
       //深度拷贝,不new的话最后results里面的每个元素都是相同的list,所以需要new来保存临时的list到results中。
        results.add(new ArrayList<Integer>(subset));
        for (int i = startIndex; i < nums.length; i++) {
            subset.add(nums[i]);
            helper(results, subset, i + 1, nums);
          //最后一个位置的元素删除,回溯到上一个节点
            subset.remove(subset.size() - 1);
        }
    }
}
View Code

思路:题目中包含“所有可能.......”,90%使用深度优先搜索解决。注意由于子集中的元素排列是非降序,所以先排序。又由于题目返回的是[[...],[...],...]所以对nums == null(null指向一个空地址)和nums.length == 0(有一个对象但为空)分别处理,前一种情况直接返回results,后一种情况results.add(new ArrayList<Integer>())后再返回results.

另一种解法: import java.util.ArrayList; import java.util.Arrays;

class Solution {
    /**
     * @param S: A set of numbers.
     * @return: A list of lists. All valid subsets.
     */
    public ArrayList<ArrayList<Integer>> subsets(int[] nums) {
        // write your code here
        ArrayList<ArrayList<Integer>> results = new ArrayList<ArrayList<Integer>>();
        ArrayList<Integer> subset = new ArrayList<Integer>();
        results.add(subset);
        if (nums ==  null || nums.length == 0) {
            return results;
        }
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            ArrayList<ArrayList<Integer>> tempResults = new ArrayList<ArrayList<Integer>>(results);
            for (ArrayList<Integer> preResult : results) {
                ArrayList<Integer> curResult = new ArrayList<Integer>(preResult);
                curResult.add(nums[i]);
                tempResults.add(curResult);
            }
            results = new ArrayList(tempResults);
        }
        return results;
    }
}
View Code

3.subsets-ii(带重复元素的子集)

class Solution {
    /**
     * @param nums: A set of numbers.
     * @return: A list of lists. All valid subsets.
     */
    public ArrayList<ArrayList<Integer>> subsetsWithDup(int[] nums) {
        // write your code here
        ArrayList<ArrayList<Integer>> results = new ArrayList<ArrayList<Integer>>();
        if (nums == null) {
            return results;
        }
        if (nums.length == 0) {
            results.add(new ArrayList<Integer>());
            return results;
        }
        Arrays.sort(nums);
        helper(results, new ArrayList<Integer>(), 0, nums);
        return results;
    }
    private void helper(ArrayList<ArrayList<Integer>> results,
                        ArrayList<Integer> subset,
                        int startIndex,
                        int[] nums) {
        results.add(new ArrayList<Integer>(subset));
        for (int i = startIndex; i < nums.length; i++) {
            if (i != 0 && nums[i - 1] == nums[i] && i != startIndex) {
                continue;
            }
            subset.add(nums[i]);
            helper(results, subset, i + 1, nums);
            subset.remove(subset.size() - 1);
        }
    }
}
View Code

给定一个可能具有重复数字(这些整数可能重复)的列表,返回其所有可能的子集。子集中的每个元素都是非降序的,两个子集间的顺序是无关紧要的,解集中不能包含重复子集。

思路:解集中不能包含重复的子集,所以使用“选代表法”去重。所以重复的数字都只选择第一个作为代表,例如{1,2(1),2(2)},规定{1,2(1)}和{1, 2(2)}重复。

if (i != 0 && nums[i - 1] == nums[i] && i != startIndex) {
     continue;
}
解释:
i != 0 防止数组越界
nums[i - 1] == nums[i] && i != startIndex 判断nums[i]前一个跟目前这个是否一致
i != startIndex 保证前一个没有被放进list: 如果nums[i - 1] 被放进list,则下一个startIndex是(i+1)也即(i-1+1)=i所以只需判断i != startIndex即可保证前一个没有被放进list
View Code

另一种解法:import java.util.ArrayList;  import java.util.Collections;

class Solution {
    /**
     * @param nums: A set of numbers.
     * @return: A list of lists. All valid subsets.
     */
    public ArrayList<ArrayList<Integer>> subsetsWithDup(int[] nums) {
        // write your code here
        ArrayList<ArrayList<Integer>> results = new ArrayList<ArrayList<Integer>>();
        ArrayList<Integer> subset = new ArrayList<Integer>();
        results.add(subset);
        if (nums ==  null || nums.length == 0) {
            return results;
        }
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            ArrayList<ArrayList<Integer>> tempResults = new ArrayList<ArrayList<Integer>>(results);
            for (ArrayList<Integer> preResult : results) {
                ArrayList<Integer> curResult = new ArrayList<Integer>(preResult);
                curResult.add(nums[i]);
                if (!tempResults.contains(curResult)) {
                    tempResults.add(curResult);
                }
            }
            results = new ArrayList(tempResults);
        }
        return results;
    }
}
View Code

4.permutations(全排列)

给定一个数字列表,返回其所有可能的排列。你可以假设没有重复数字。

class Solution {
    /**
     * @param nums: A list of integers.
     * @return: A list of permutations.
     */
    public List<List<Integer>> permute(int[] nums) {
        // write your code here
        ArrayList<List<Integer>> results = new ArrayList<List<Integer>>();
        if (nums == null) {
            return results;
        }
        if (nums.length == 0) {
            results.add(new ArrayList<Integer>());
            return results;
        }
        ArrayList<Integer> list = new ArrayList<Integer>();
        helper(results, list, nums);
        return results;
    }
    private void helper(ArrayList<List<Integer>> results,
                        ArrayList<Integer> list,
                        int[] nums) {
        if (list.size() == nums.length) {
            results.add(new ArrayList<Integer>(list));
        }
        for (int i = 0; i < nums.length; i++) {
            if (list.contains(nums[i])) {
                continue;
            }
            list.add(nums[i]);
            helper(results, list, nums);
            list.remove(list.size() - 1);
        }
    }
}
View Code

注意:无需排序

5.permutations-ii(带重复元素的排列)

给出一个具有重复数字的列表,找出列表所有不同的排列。

class Solution {
    /**
     * @param nums: A list of integers.
     * @return: A list of unique permutations.
     */
    public List<List<Integer>> permuteUnique(int[] nums) {
        // Write your code here
        ArrayList<List<Integer>> results = new ArrayList<List<Integer>>();
        if (nums == null) {
            return results;
        }
        if (nums.length == 0) {
            results.add(new ArrayList<Integer>());
            return results;
        }
        ArrayList<Integer> list = new ArrayList<Integer>();
        Arrays.sort(nums);
        int[] visited = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            visited[i] = 0;
        }
        helper(results, list, nums, visited);
        return results;
    }
    private void helper(ArrayList<List<Integer>> results,
                        ArrayList<Integer> list,
                        int[] nums,
                        int[] visited) {
        if (list.size() == nums.length) {
            results.add(new ArrayList<Integer>(list));
        }
        for (int i = 0; i < nums.length; i++) {
            if ((i != 0 && visited[i - 1] == 0 && nums[i - 1] == nums[i]) || visited[i] == 1) {
                continue;
            }
            visited[i] = 1;
            list.add(nums[i]);
            helper(results, list, nums, visited);
            list.remove(list.size() - 1);
            visited[i] = 0;
        }
    }
}
View Code

注意:先排序,使用visited数据记录该数字是否被访问,“选代表法“去重。

if ( visited[i] == 1 || ( i != 0 && nums[i] == nums[i - 1]
            && visited[i-1] == 0)){
                continue;
}
上面的判断主要是为了去除重复元素影响。
比如,给出一个排好序的数组,[1,2,2],那么第一个2和第二2如果在结果中互换位置, 我们也认为是同一种方案,所以我们强制要求相同的数字,原来排在前面的,在结果 当中也应该排在前面,这样就保证了唯一性。所以当前面的2还没有使用的时候,就不应该让后面的2使用。
View Code

6.hash-function(哈希函数)

在数据结构中,哈希函数是用来将一个字符串(或任何其他类型)转化为小于哈希表大小且大于等于零的整数。一个好的哈希函数可以尽可能少地产生冲突。一种广泛使用的哈希函数算法是使用数值33,假设任何字符串都是基于33的一个大整数,比如:

hashcode("abcd") = (ascii(a) * 33的3次方 + ascii(b) * 33的2次方 + ascii(c) *33 + ascii(d)) % HASH_SIZE 

                              = (97* 33的3次方 + 98 * 33的2次方 + 99 * 33 +100) % HASH_SIZE

                              = 3595978 % HASH_SIZE

其中HASH_SIZE表示哈希表的大小(可以假设一个哈希表就是一个索引0 ~ HASH_SIZE-1的数组)。给出一个字符串作为key和一个哈希表的大小,返回这个字符串的哈希值。

class Solution {
    /**
     * @param key: A String you should hash
     * @param HASH_SIZE: An integer
     * @return an integer
     */
    public int hashCode(char[] key, int HASH_SIZE) {
        // write your code here
        long ans = 0;
        for (int i = 0; i < key.length; i++) {
            ans = (ans * 33 + (int) key[i]) % HASH_SIZE;
        }
        return (int) ans;
    }
};
View Code

7.strstr-ii【Rabin-Karp算法】【hard】

在O(n + m)时间内实现strStr函数。

public class Solution {
    /**
     * @param source a source string
     * @param target a target string
     * @return an integer as index
     */
    public int BASE = 1000000;
    public int strStr2(String source, String target) {
        // Write your code here
        if (source == null || target == null) {
            return -1;
        }
        int m = target.length();
        if (m == 0) {
            return 0;
        }
        //31^m
        int power = 1;
        for (int i = 0; i < m; i++) {
            power = (power * 31) % BASE;
        }
        //targetCode
        int targetCode = 0;
        for (int i = 0; i < m; i++) {
            targetCode = (targetCode * 31 + target.charAt(i)) % BASE;
        }
        //hashCode
        int hashCode = 0;
        for (int i = 0; i < source.length(); i++) {
            //abc + d
            hashCode = (hashCode * 31 + source.charAt(i)) % BASE;
            if (i < m - 1) {
                continue;
            }
            //   i
            //abcd - a
            if (i >= m) {
                hashCode = hashCode - (source.charAt(i - m) * power) % BASE;
                if (hashCode < 0) {
                    hashCode += BASE;
                }
            }
            //double check the string
            if (hashCode == targetCode) {
                if (source.substring(i - m + 1, i + 1).equals(target)) {
                    return i - m + 1;
                }
            }
        }
        return -1;
    }
}
View Code
原文地址:https://www.cnblogs.com/struggleli/p/6756364.html