双非本科准备秋招(8.1)——力扣哈希

LeetCode

1、49. 字母异位词分组

学到的知识:

1、String的toCharArray()方法能返回一个Char类型的数组,自己发现对String学的还不系统,于是重新学了下String。

2、new ArrayList()可以接收一个Collection对象

3、map的keySet和values方法,分别返回Set和Collection类型的对象。

分析:

字母异位词是乱序的,也就是说,如果排序的话,那么异位词就相等了,比如"ab"、"ba",排序之后都是"ab"。

所以,我们可以遍历这个字符串数组,把每个字符串先排序,然后用排序过后的字符串当作key,查找哈希表,将原先字符串添加进去。

哈希表是String-List,key是排序后的字符串,value是链表,代表key的异位词。

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());
    }
}

2、217. 存在重复元素

纯纯水题,建个哈希表,找一遍就行了。

不过一开始我的思维固化了,见什么都用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;
    }
}

3、136. 只出现一次的数字

借鉴上一个题目的思路,出现过了就加入(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;
    }
}

4、242. 有效的字母异位词

这个题比第一题简单,排个序,直接比较,思路和第一题是一样的。

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']++;
        }
    }
}

5、387.字符串中的第一个唯一字符

第一次,想复杂了。

我想的是建立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;
    }
}

6、349. 两个数组的交集

 思路:遍历第一个数组,加入哈希表(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;
    }
}

7、202.快乐数

我一开始看到无限循环,以为暗示的是没有规律,后来想想,题目说的是循环但始终不到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);
        }
    }
}

你可能感兴趣的:(leetcode,算法,求职招聘)