Hash Table Three

 (1)Happy Number

解题思路:使用HashSet,注意HashSet中的元素不能重复,所以不是happy number的数字要无限循环,一定要重复,就会返回false.

代码如下:

 1 public class Solution {
 2     public boolean isHappy(int n) {
 3         Set<Integer> set = new HashSet<>();
 4         int sum, remain;
 5         while (set.add(n)) {
 6             sum = 0;
 7             while (n > 0) {
 8                 remain = n % 10;
 9                 sum += remain * remain;
10                 n /= 10;
11             }
12             if (sum == 1) {
13                 return true;
14             } else {
15                 n = sum;
16             }
17         }
18         return false;
19     }
20 }
View Code

注意:while(set.add(n))这个判断条件。当不是happy number的数字无限循环时一定会重复,就不能继续加入就返回false.

(2)Find All Anagrams in a String【理解不透】

代码如下:

 1 public class Solution {
 2     public List<Integer> findAnagrams(String s, String p) {
 3         List<Integer> list = new ArrayList<>();
 4     if (s == null || s.length() == 0 || p == null || p.length() == 0) return list;
 5     int[] hash = new int[256]; //character hash
 6     //record each character in p to hash
 7     for (char c : p.toCharArray()) {
 8         hash[c]++;
 9     }
10     //two points, initialize count to p's length
11     int left = 0, right = 0, count = p.length();
12     while (right < s.length()) {
13         //move right everytime, if the character exists in p's hash, decrease the count
14         //current hash value >= 1 means the character is existing in p
15         if (hash[s.charAt(right)] >= 1) {
16             count--;
17         }
18         hash[s.charAt(right)]--;
19         right++;
20         //when the count is down to 0, means we found the right anagram
21         //then add window's left to result list
22         if (count == 0) {
23             list.add(left);
24         }
25         //if we find the window's size equals to p, then we have to move left (narrow the window) to find the new match window
26         //++ to reset the hash because we kicked out the left
27         //only increase the count if the character is in p
28         //the count >= 0 indicate it was original in the hash, cuz it won't go below 0
29         if (right - left == p.length() ) {
30             if (hash[s.charAt(left)] >= 0) {
31                 count++;
32             }
33             hash[s.charAt(left)]++;
34             left++;
35         }
36     }
37         return list;
38     }
39 }
View Code

解题思路:

使用滑动窗口,使得时间复杂度为为O(n),这就是算法的力量!

算法介绍:

(1)count= p.length(),用来表示目前窗口中的字符和p的差异度(由于窗口最大时(为p.length())才有可能使count为0,所以count为0时窗口中的字符与p为Anagrams)。count差异度的含义:一开始窗口左右指针都指向第一个,所以差异度最大为p.length();当窗口中进来一个p中有的字符,差异度就减一,出去一个p中有的差异度就增一;至于进来或出去的是p中没有的,则count不变,反正窗口的最大值也不过是p.length()。

(2)窗口的左右两个指针:left和right,分别指向窗口的左端和右端。

滑动窗口具体操作:

先滑动右指针,

1.1 加进来的字符如果该字符在数组hash的计数中大于等于一意味着该字符在p中出现,则count减一,否则不做操作,

1.2无论在不在p中出现,数组hash该字符相应位置计数都减一。

1.3如果count为0,则将此时的left值加入到list中。

判断如果窗口长度到达p.length(),开始滑动左指针:

2.1被踢出窗口的那个字符如果在数组hash的计数中非负意味着原来在p中出现,此时要踢出,则差异度count增一,不在则不做操作。

2.2无论在不在数组hash该字符相应位置计数都加一

3.上面1.1和2.1操作的原理:hash中的记录的数据是代表p中含有的的每个字符的数量去掉当前窗口中存在的p字符串中每个字符的数量,一开始窗口大小为0,啥都不存在,自然hash中记录的就是全部p中含有的的每个字符的数量,如果窗口中有一个,则hash相应的记录中就少一个。如果窗口中多包含一个p中没有的(或者包含的某一个字符的数量比p中有的还多),那么这时候,hash中相应的记录值就会变成负数,代表当前窗口中包含相应字符的“多余”的数量。

      所以当进来一个的时候,如果相应记录为非负,那么这个进入是有意义的,则差异度(count)减一;当出去一个的时候,如果相应记录为非负,那么这个出去是有意义的,则差异度(count)加一。

4.hash用到哈希表思想,用来记录p中每一种字符分别有多少个。

(3)Bulls and Cows

代码如下:

 1 public class Solution {
 2     public String getHint(String secret, String guess) {
 3         int[] count = new int[10];
 4         int bulls = 0;
 5         int cows = 0;
 6         for (int i = 0; i < secret.length(); i++) {
 7             int s = secret.charAt(i) - '0';
 8             int g = guess.charAt(i) - '0';
 9             if (s == g) {
10                 bulls++;
11             } else {
12                 if (count[s] < 0) {
13                     cows++;
14                 }
15                 if (count[g] > 0) {
16                     cows++;
17                 }
18                 count[s]++;
19                 count[g]--;
20             }
21         }
22         return bulls + "A" + cows + "B";
23     }
24 }
View Code

解题思路:

使用一个数组记录数字的出现,在secret中出现增加计数,在guess中出现减少计数。使用for循环遍历一次,如果s和g出现完全匹配,bulls计数加一.否则,如果此时s的计数小于零,说明guess中已有该数字,cows加一。如果此时g的计数大于零,说明secret中已有该数字,cows加一。然后s计数加一,g计数减一。

(4)Isomorphic Strings

解题思路一:主要想法是存储两个字符串中当前(第i个)字符的最后出现的位置。如果先前存储的位置不同,则他们同时出现在当前第i个位置是不可能的,故返回false。

代码如下:

 1 public class Solution {
 2     public boolean isIsomorphic(String s1, String s2) {
 3         int[] m = new int[512];
 4         for (int i = 0; i < s1.length(); i++) {
 5             if (m[s1.charAt(i)] != m[s2.charAt(i) + 256]) {
 6                 return false;
 7             }
 8             m[s1.charAt(i)] = m[s2.charAt(i) + 256] = i + 1;
 9         }
10         return true;
11     }
12 }
View Code

解题思路二:使用一个哈希表map维护两个字符串中字符的映射关系,同时用一个set保存映射的值。(s[i], t[i]),如果s[i]键没有在map中出现过并且t[i]没有在set中出现过,就加入到映射关系中。t[i]值已经出现过,说明是多对一映射,不符合返回false。s[i]键如果已经出现过,设为s[k],对应的映射值为t[k]),即s[i]==s[k],则找出s[k]的对对应值t[k],如果t[i]!=t[k],说明一个同一个字符存在两个不同的映射,两个字符串不是同构的,返回false,继续处理下一个字符,直到结束。 

代码如下:

 1 public class Solution {       
 2     public boolean isIsomorphic(String s, String t) {   
 3         Map<Character, Character> map = new HashMap<Character, Character>();  
 4         Set<Character> set = new HashSet<Character>();  
 5           
 6         for(int i=0; i<s.length(); i++) {  
 7             char c1 = s.charAt(i);  
 8             char c2 = t.charAt(i);  
 9               
10             if(map.containsKey(c1)) {  
11                 if(map.get(c1) != c2) return false;  
12             } else {  
13                 if(set.contains(c2)) return false;  
14                 else {  
15                     map.put(c1, c2);  
16                     set.add(c2);  
17                 }  
18             }  
19         }  
20         return true;  
21     }  
22 }  
View Code
原文地址:https://www.cnblogs.com/struggleli/p/6164308.html