学到的知识:
1、String的toCharArray()方法能返回一个Char类型的数组,自己发现对String学的还不系统,于是重新学了下String。
2、new ArrayList()可以接收一个Collection对象
3、map的keySet和values方法,分别返回Set和Collection类型的对象。
分析:
字母异位词是乱序的,也就是说,如果排序的话,那么异位词就相等了,比如"ab"、"ba",排序之后都是"ab"。
所以,我们可以遍历这个字符串数组,把每个字符串先排序,然后用排序过后的字符串当作key,查找哈希表,将原先字符串添加进去。
哈希表是String-List
class Solution {
public List> groupAnagrams(String[] strs) {
HashMap> map = new HashMap();
for(String s : strs){
char[] chars = s.toCharArray();
Arrays.sort(chars);
String temp = new String(chars);
List list = map.get(temp);
if(list == null){
list = new ArrayList<>();
map.put(temp, list);
}
list.add(s);
}
return new ArrayList(map.values());
}
}
纯纯水题,建个哈希表,找一遍就行了。
不过一开始我的思维固化了,见什么都用HashMap。
class Solution {
public boolean containsDuplicate(int[] nums) {
HashMap map = new HashMap<>();
for(Integer x : nums){
if(map.containsKey(x)){
return true;
}
map.put(x, 1);
}
return false;
}
}
用HashSet更好,set的add()方法返回boolean值,代表是否添加成功,如果有重复元素那就添加失败了,就返回false。
class Solution {
public boolean containsDuplicate(int[] nums) {
HashSet set = new HashSet<>();
for(Integer x : nums){
if(!set.add(x)){
return true;
}
}
return false;
}
}
借鉴上一个题目的思路,出现过了就加入(add())失败,那么就删除这个值(remove())。
注意如何处理返回值,需要把set转成数组:通过set.toArray()方法,把set转成数组,需要把new Integer[set.size()]作为参数传进set.toArray()方法。因为答案只有一个,所以只需要返回下标为0的元素就行,这个方法里有个实例对象就行,大小任意。写成new Integer[0]也一样。
class Solution {
public int singleNumber(int[] nums) {
HashSet set = new HashSet<>();
for(Integer x : nums){
if(!set.add(x)){
set.remove(x);
}
}
return set.toArray(new Integer[1])[0];
}
}
另一种用异或的思路,异或就是相同为0,不同为1。
结论1:那么一个数自己和自己异或,都相同,结果是0;
结论2:一个数和0异或,原数是0的地方还是0(相同),是1的地方还是1(不同),所以不变。
我们只需要用0和数组中每个数异或,那么结果就是唯一的那个数,还是很巧妙的。
class Solution {
public int singleNumber(int[] nums) {
int ans = 0;
for(int x : nums) ans ^= x;
return ans;
}
}
这个题比第一题简单,排个序,直接比较,思路和第一题是一样的。
class Solution {
public boolean isAnagram(String s, String t) {
char[] c1 = s.toCharArray();
char[] c2 = t.toCharArray();
Arrays.sort(c1);
Arrays.sort(c2);
String s1 = new String(c1);
String s2 = new String(c2);
return s1.equals(s2);
}
}
另一种方法,这个方法第一题也能用,不过我没写。
可以建立数组,因为题目说了小写字母,所以26位就够了,字母-'a'得到的就是数组中的下标,我们统计每个字母出现的次数(hashLoop方法)。
最后遍历这两个数组,看看出现的次数相不相等。
class Solution {
public boolean isAnagram(String s, String t) {
int[] arr1 = new int[26];
int[] arr2 = new int[26];
hashLoop(s, arr1);
hashLoop(t, arr2);
for(int i = 0; i < 26; i++){
if(arr1[i] != arr2[i]){
return false;
}
}
return true;
}
public void hashLoop(String s, int[] arr){
for(int i = 0; i < s.length(); i++){
arr[s.charAt(i)-'a']++;
}
}
}
第一次,想复杂了。
我想的是建立26个坑位的数组,还是字符-‘a’代表数组下标。然后数组记录的是它第一次出现的位置。
初始化数组,赋值为-2,-2代表未赋值。-1代表元素重复了。
遍历数组,如果等于-2并且不等于-1,即未被赋值且不重复,那么就把元素下标赋值给这个坑位。
如果不等于-2,说明元素重复,那么就赋值-1
最后遍历一遍,找到最小的元素,就是下标最小的。
class Solution {
public int firstUniqChar(String s) {
int[] arr = new int[26];
for(int i = 0; i < 26; i++) arr[i] = -2;
for(int i = 0; i < s.length(); i++){
int index = s.charAt(i)-'a';
if(arr[index] != -1 && arr[index] == -2){//没有值,赋值。
arr[index] = i;
}
else if(arr[index] != -2){//有值了,-1
arr[index] = -1;
}
}
int ans = 1000000;
for(int i = 0; i < 26; i++){
if(arr[i] != -1 && arr[i] != -2 && arr[i] < ans)
ans = arr[i];
}
return ans==1000000?-1:ans;
}
}
改进一下,根本没必要记录下标啊,数组还是记录出现的次数。
然后再遍历一下原字符串不就行了,看看每个字符串在数组中是不是1,是1代表出现了1次,而且是字符串第一个不重复的元素,直接返回当前遍历的下标就行了。
class Solution {
public int firstUniqChar(String s) {
int[] arr = new int[26];
char[] chars = s.toCharArray();
for(char c : chars){
arr[c-'a']++;
}
for(int i = 0; i < chars.length; i++){
if(arr[chars[i] - 'a'] == 1){
return i;
}
}
return -1;
}
}
思路:遍历第一个数组,加入哈希表(Set)中,遍历第二个数组,在哈希表中查找。
注意返回不能直接用 ans.toArray(new Integer[0]),因为这个返回的是Integer类型的数组,题目需要返回的是int类型的数组。Integer和int可以进行相互赋值,因为java做了自动拆箱和自动装箱的操作,数组不可以。
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
HashSet set = new HashSet<>();
HashSet ans = new HashSet<>();
for(int x : nums1){
set.add(x);
}
for(int x : nums2){
if(set.contains(x)){
ans.add(x);
}
}
//处理数据
int[] arr = new int[ans.size()];
int cnt = 0;
for(int s : ans){
arr[cnt++] = s;
}
return arr;
}
}
我一开始看到无限循环,以为暗示的是没有规律,后来想想,题目说的是循环但始终不到1,意味着一定会有一个重复的循环,所以暴力做就行了,把每次得到的结果都加入哈希中,如果发现重复了就说明会无限循环了,返回false,如果等于1了,就返回true。
class Solution {
public int sum(int n){
int ans = 0;
while(n != 0){
ans += (n%10)*(n%10);
n /= 10;
}
return ans;
}
public boolean isHappy(int n) {
HashSet set = new HashSet<>();
while(true){
if(n == 1) return true;
n = sum(n);
if(set.contains(n)){
return false;
}
set.add(n);
}
}
}