首页 > 代码库 > Chapter one
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; } }
思路:双重循环即可解决。注意第一重循环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); } } }
思路:题目中包含“所有可能.......”,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; } }
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); } } }
给定一个可能具有重复数字(这些整数可能重复)的列表,返回其所有可能的子集。子集中的每个元素都是非降序的,两个子集间的顺序是无关紧要的,解集中不能包含重复子集。
思路:解集中不能包含重复的子集,所以使用“选代表法”去重。所以重复的数字都只选择第一个作为代表,例如{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
另一种解法: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; } }
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); } } }
注意:无需排序
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; } } }
注意:先排序,使用visited数据记录该数字是否被访问,“选代表法“去重。
if ( visited[i] == 1 || ( i != 0 && nums[i] == nums[i - 1] && visited[i-1] == 0)){ continue; } 上面的判断主要是为了去除重复元素影响。 比如,给出一个排好序的数组,[1,2,2],那么第一个2和第二2如果在结果中互换位置, 我们也认为是同一种方案,所以我们强制要求相同的数字,原来排在前面的,在结果 当中也应该排在前面,这样就保证了唯一性。所以当前面的2还没有使用的时候,就不应该让后面的2使用。
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; } };
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; } }
Chapter one