0
点赞
收藏
分享

微信扫一扫

算法 LeetCode题目解析--03(两类查找)

雨鸣静声 2022-04-18 阅读 46
java算法

目录

1.两类查找

例题1 两个数组的交集:leetcode 349

例题2 两个数组的交集 II:leetcode 350

 例题3  有效的字母异位词:leetcode 242

   例题4 : 快乐数  leetcode202

 例题5: 单词找规律  leetcode 290

例题6: 同构字符串  leetcode 205

例题7: 按照字符串出现的顺序重组字符串  leetcode 451

 例题7: 一个使用查找表的经典问题  leetcode 1  两数之和

 例题8:  三数之和  leetcode 15 


1.两类查找

  

例题1 两个数组的交集:leetcode 349

     

解题思路:这是典型的第一类查找,查找有无,所以我们会想到使用Set,将第一个数组的元素放到数组中,再判断第二个数组的元素是否存在于第一个元素的数组中,如果存在则加入到一个新的Set,最后返回这个新的Set

public int[] intersection(int[] nums1, int[] nums2) {

        Set<Integer> temp = new HashSet<>();
        Set<Integer> re = new HashSet<>();
        for (int i = 0; i < nums1.length; i++) {
            temp.add(nums1[i]);
        }

        for (int i = 0; i < nums2.length; i++) {
            if (temp.contains(nums2[i])) {
                re.add(nums2[i]);
            }
        }

        int[] reArr = new int[re.size()];


        Object[] objects = re.toArray();
        for (int i = 0; i < objects.length; i++) {
            reArr[i] = (int) objects[i];
        }
        return reArr;

    }

例题2 两个数组的交集 II:leetcode 350

 解题思路:这次跟上一题相比我们需要考虑元素重复的情况,所以将Set换成List,判断是否存在的条件依然不变,只是需要判断完成后要删除元素。

但是这属于第二种查找,键值对的类型,需要用键值对来记录元素出现的频次

public int[] intersect(int[] nums1, int[] nums2) {

        List<Integer> temp = new ArrayList<>();
        List<Integer> re = new ArrayList<>();
        for (int i = 0; i < nums1.length; i++) {
            temp.add(nums1[i]);
        }

        for (int i = 0; i < nums2.length; i++) {
            if (temp.contains(nums2[i])) {
                re.add(nums2[i]);
                temp.remove(Integer.valueOf(nums2[i]));
            }
        }

        int[] reArr = new int[re.size()];


        Object[] objects = re.toArray();
        for (int i = 0; i < objects.length; i++) {
            reArr[i] = (int) objects[i];
        }
        return reArr;
    }

 思考,在数组有序的情况下,我们就可以不借用辅助的数据结构,而是可以很容易的实现一个O(logn)级别的算法来实现查找,比如二分查找。

  还有一类的查找是非常快的,就是哈希表,但是他也失去了数据的顺序性

 例题3  有效的字母异位词:leetcode 242

  

  • s 和 t 仅包含小写字母

解题思路:

 解法1:t 是 ss 的异位词等价于「两个字符串排序后相等」,因此我们可以对字符串 ss 和 tt 分别排序,看排序后的字符串是否相等即可判断。此外,如果 ss 和 tt 的长度不同,tt 必然不是 ss 的异位词。

时间复杂度是O(nlogn),空间复杂度O(logn)

解法2:使用哈希表来记录字符出现的频次

tt 是 ss 的异位词等价于「两个字符串中字符出现的种类和次数均相等」。由于字符串只包含 2626 个小写字母,因此我们可以维护一个长度为 2626 的频次数组 \textit{table}table,先遍历记录字符串 ss 中字符出现的频次,然后遍历字符串 tt,减去 \textit{table}table 中对应的频次,如果出现 \textit{table}[i]<0table[i]<0,则说明 tt 包含一个不在 ss 中的额外字符,返回 \text{false}false 即可。

时间复杂度O(n)  空间复杂度O(s)

public boolean isAnagram(String s, String t) {
       if (s.length() != t.length()) {
            return false;
        }
        int[] table = new int[26];
        for (int i = 0; i < s.length(); i++) {
            table[s.charAt(i) - 'a']++;
        }
        for (int i = 0; i < t.length(); i++) {
            table[t.charAt(i) - 'a']--;
            if (table[t.charAt(i) - 'a'] < 0) {
                return false;
            }
        }
        return true;

    }

如果t跟s不仅仅包含的是小写字母吗,而是所有的字符,比如包含了大写的字母,这个时候可以扩大数组的长度为256,但是如果我还包含了中文,这个时候长度会很大,所以这个时候需要真正的hash表来存贮字符出现的频次。

 public static boolean isBigAnagram(String s, String t) {
        if (s.length() != t.length()) {
            return false;
        }
        Map<Character, Integer> table = new HashMap<>();
        for (int i = 0; i < s.length(); i++) {
            table.put(s.charAt(i), table.getOrDefault(s.charAt(i), 0) + 1);
        }
        for (int i = 0; i < t.length(); i++) {
            table.put(t.charAt(i), table.getOrDefault(t.charAt(i), 0) - 1);
            if (table.get(t.charAt(i)) < 0) {
                return false;
            }
        }
        return true;
    }

   例题4 : 快乐数  leetcode202

解题思路:

  解法一  快慢指针法

  解法二 用哈希集合检测循环,他有两种的可能一种是循环到结果为1

  

 一种是进入一个死循环

 

 有没有第三种可能 值会愈来愈大  不会进入死循环呢?答案是没有的,对于一个一位数来说,他分解后最大的值不会超过81,二位数分解后最大的值不会超过162,三位数分解后最大的值不会超过243,以此类推,最后都会在一个可控的范围内循环,所以用一个哈希表存储每次循环出现过的数字,当出现相同的数字的 时候,就说明已经可以返回false了。

  public static boolean isHappy(int n) {
        Set<Integer> stringList = new HashSet<>();
        while (n != 1) {
            n = getNext(n);
            if (stringList.contains(n)) {
                return false;
            }else {
                stringList.add(n);
            }
        }
        return true;
    }

    private static int getNext(int n) {
        int re = 0;
        while (n > 0) {
            int i = n % 10;
            re = re + i * i;
            n = n / 10;
        }
        return re;
    }

时间复杂度:O(logn)

空间复杂度:O(logn)

 例题5: 单词找规律  leetcode 290

 解题思路:

      我们需要判断字符与字符串之间是否恰好一一对应。即任意一个字符都对应着唯一的字符串,任意一个字符串也只被唯一的一个字符对应。在集合论中,这种关系被称为「双射」。

想要解决本题,我们可以利用哈希表记录每一个字符对应的字符串,以及每一个字符串对应的字符。然后我们枚举每一对字符与字符串的配对过程,不断更新哈希表,如果发生了冲突,则说明给定的输入不满足双射关系。

需要注意的是插入的是同一个对象返回来的才是同一个对象

代码:

    public static boolean wordPattern(String pattern, String s) {
        Map<Object, Object> strMap = new HashMap<>();
        Map<Object, Object> cha = new HashMap<>();
        String[] s1 = s.split(" ");
        if (s1.length != pattern.length()) {
            return false;
        }
        //果key重复了,返回的是map.get(key),
        //  注意这里是Integer  把同一个Integer作为value存进去 当hash冲突的时候返回来的才是同一个对象,如果存的是int  则返回来的是两个不同的Integer
        for (Integer i = 0; i < s1.length; i++) {
            if (strMap.put(s1[i], String.valueOf(i)) != cha.put(pattern.charAt(i), String.valueOf(i))) {
                return false;
            }
        }
        return true;
    }

例题6: 同构字符串  leetcode 205

  

 

 解题思路:这个题目和上个题目的解题思路是一样的,不再多说

 代码:

 public boolean isIsomorphic(String s, String t) {
        if (s.length() != t.length()) {
            return false;
        }
        Map<Character, Integer> sMap = new HashMap<>();
        Map<Character, Integer> tMap = new HashMap<>();
        for (Integer i = 0; i < s.length(); i++) {
            if (sMap.put(s.charAt(i), i) != tMap.put(t.charAt(i), i)) {
                return false;
            }

        }
        return true;

    }

例题7: 按照字符串出现的顺序重组字符串  leetcode 451

 

 

 解题思路:

   当出现频次的时候,肯定会想到使键值的方式来存储字符出现的频率,但是还有一个频率次数的排序。这是一个对map的value进行排序,所以需要将map转化为一个List,然后对value进行排序就可以达到目的。有序的Map我们会想到的是TreeMap,但是TreeMap是对Key进行自然排序

代码:

    public String frequencySort(String s) {
        Map<Character, Integer> sMap = new HashMap<>();
        for (int i = 0; i < s.length(); i++) {
            sMap.put(s.charAt(i), sMap.getOrDefault(s.charAt(i), 0) + 1);
        }

        List<Map.Entry<Character, Integer>> list = new ArrayList<>(sMap.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<Character, Integer>>() {
            @Override
            public int compare(Map.Entry<Character, Integer> o1, Map.Entry<Character, Integer> o2) {
                return -(o1.getValue().compareTo(o2.getValue()));
            }
        });

        StringBuilder stringBuilder = new StringBuilder();
        for (Map.Entry<Character, Integer> characterIntegerEntry : list) {
            for (int i = 0; i < characterIntegerEntry.getValue(); i++) {
                stringBuilder.append(characterIntegerEntry.getKey());
            }
        }
        return stringBuilder.toString();
    }

复杂度分析

时间复杂度:O(n + k \log k)O(n+klogk),其中 nn 是字符串 ss 的长度,kk 是字符串 ss 包含的不同字符的个数,这道题中 ss 只包含大写字母、小写字母和数字,因此 k=26 + 26 + 10 = 62k=26+26+10=62。
遍历字符串统计每个字符出现的频率需要 O(n)O(n) 的时间。
将字符按照出现频率排序需要 O(k \log k)O(klogk) 的时间。
生成排序后的字符串,需要遍历 kk 个不同字符,需要 O(k)O(k) 的时间,拼接字符串需要 O(n)O(n) 的时间。
因此总时间复杂度是 O(n + k \log k + k + n)=O(n + k \log k)O(n+klogk+k+n)=O(n+klogk)。

空间复杂度:O(n + k)O(n+k),其中 nn 是字符串 ss 的长度,kk 是字符串 ss 包含的不同字符的个数。空间复杂度主要取决于哈希表、列表和生成的排序后的字符串。

 例题7: 一个使用查找表的经典问题  leetcode 1  两数之和

解题思路:

  思路1: 暴力解法,遍历两次 找到和等于目标值target的坐标返回,这个算法的时间复杂度为O(n2)

  思路2:采用双索引指正碰撞,但是数组是无序的,所以要先拍个序,时间复杂度O(nlogn),然后双指针碰撞,O(n),所以总的时间复杂度是O(nlogn)+O(n),但是要返回的是排序前的索引

 思路3:将数组的元素放到一个哈希表里面,遍历哈希表,找到target-v存在的即可。

  

代码:

public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        int a = 0, b = 0;
        for (int i = 0; i < nums.length; i++) {
            int temp = target - nums[i];
            if (map.keySet().contains(temp)) {
                a = map.get(temp);
                b = i;
                return new int[]{a, b};
            }
            map.put(nums[i], i);
        }
        return null;
    }

时间复杂度为O(n)

空间复杂度O(n)

 例题8:  三数之和  leetcode 15 

 

举报

相关推荐

0 条评论