算法快与慢--哈希+双指针

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

目前大概能写简单或者中等题了,正在追求优解


一、哈希

hash的原理在多线程里有讲,表面是一个连续的数组,在碰到hash冲突的时候会退为链表和红黑树,当一个链表上挂的东西过长的时候就会扩容,hash的初始化和扩容容量和他的概率有关,大概就是每个链表上挂8个的概率很小,所以以这个理由扩容。

hash在leetcode中主要表现为查找,因为一个东西hash后到List中去找到的时间复杂度是O(1),没有链表时就是比较hash值直接查找,有链表时会从头一个个比值,总的来说还是O(1),根据这个原理我认为hash是便于查找,不便于大量数据插入。

题目的范式是hash.containsKey(key)

不理解hash查找之前

java 复制代码
class Solution {
    public int[] twoSum(int[] nums, int target) {
        int i=0;
        int[] arr=new int[2];
        while( i <=nums.length-1){
        int temp=target-nums[i];
        for(int j=i+1;j<=nums.length-1;j++){
            if(nums[j]==temp){
                arr[0]=i;
                arr[1]=j;
                return arr;
            }
        }
        i++;
    }
    return arr;
}
}

想法基本没有问题,hash之后

java 复制代码
class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer,Integer> hash=new HashMap<Integer,Integer>();
        for(int i=0;i<nums.length;i++){
        if(!hash.containsKey(target-nums[i])){
            hash.put(nums[i],i);
        }else{
            return new int[]{hash.get(target-nums[i]),i};
        }
        }
        return new int[0];
    }
}

这里外层是一次循环O(n),内层是hashO(1),相乘还是O(n),差距很大了

这题在ai帮助下想到了序列化key,然后hash,然后有点追求速度的想法。慢的原因是用了StringBuffer,这个有锁所以慢,后来用了StringBuilder就快一些。还有一种方法是排序,但是排序可能没有字母表好。

java 复制代码
class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        List finallist=new ArrayList();
        Map<String,List<String>> hash=new HashMap();
        for(String word:strs){
            int[] wordchar=new int[26];
            for(int i=0;i<word.length();i++){
            wordchar[word.charAt(i)-'a']++;
            }
            StringBuffer buffer=new StringBuffer();
            for(int i=0;i<26;i++){
            buffer.append(wordchar[i]).append(',');
            }
            if(!hash.containsKey(buffer.toString())){
                hash.put(buffer.toString(),new ArrayList<String>());
            }
            hash.get(buffer.toString()).add(word);
        }
        finallist.addAll(hash.values());
        return finallist;
    }
}
java 复制代码
class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        List<List<String>> finallist=new ArrayList<>();
        Map<String,List<String>> hash=new HashMap<>();
        for(String word:strs){
            int[] wordchar=new int[26];
            for(int i=0;i<word.length();i++){
            wordchar[word.charAt(i)-'a']++;
            }
            StringBuilder buffer=new StringBuilder();
            for(int i=0;i<26;i++){
            buffer.append(wordchar[i]).append(',');
            }
            if(!hash.containsKey(buffer.toString())){
                hash.put(buffer.toString(),new ArrayList<String>());
            }
            hash.get(buffer.toString()).add(word);
        }
        finallist.addAll(hash.values());
        return finallist;
    }
}

这题看了答案,不能有n-1.然后了解到for循环一直没有进去就不算时间复杂度.。除了提前返回,没有任何优化。

java 复制代码
class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> hash=new HashSet<Integer>();
        for(int n: nums){
            hash.add(n);
        }
        int max=0;

        for(int n:nums){
            if(!hash.contains(n-1)){
                int cur=1;
                while(hash.contains(n+1)){
                    cur++;
                    n++;
                }
                if(cur>nums.length/2){
                    return cur;
                }
                max=Math.max(max,cur);
            }
        }
        return max;
    }
}

二、双指针(未完)

这题想到了多次挪零,也普及了三种双指针:普通、快慢、滑窗。看到考的是双指针,就理所应当想到了将零与末尾元素交换,但是这样又无序了,有点矛盾,只能一个个挪0.

java 复制代码
class Solution {
    public void moveZeroes(int[] nums) {
        int l=0,r=0;
        for(;r<nums.length;r++){
            if(nums[r]!=0){
                swap(nums,l,r);
                l++;
            }
        }
    }
    public void swap(int[] nums,int l,int r){
        int tmp;
        tmp=nums[l];
        nums[l]=nums[r];
        nums[r]=tmp;
    } 
}

了解到下标就是减现有0的个数,但是并没有更快

java 复制代码
class Solution {
    public void moveZeroes(int[] nums) {
        int n,count=0;

        if(nums.length==1){
            return;
        }

        for(int i=0;i<nums.length;i++){
            if(nums[i]!=0 && count==0){
                continue;
            }
            if(nums[i]!=0 ){
                nums[i-count]=nums[i];
                nums[i]=0;
            }else{
                count++;
            }
            
        }
    }
}

方法没问题,问题在于非零元素的两次赋值,既要挪零,又要将非零元素置零

java 复制代码
class Solution {
    public void moveZeroes(int[] nums) {
        int cur = 0;
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] != 0) {
            nums[cur] = nums[i];
            cur++;
        }
    }
    for (int i = cur; i < nums.length; i++) {
        nums[i] = 0;
    }
    }
}

虽然没有做出来,但是整体结构已经很像了,主要是数学功底不足,证明不出

java 复制代码
class Solution {
    public int maxArea(int[] height) {
        int l=0,r=height.length-1;
        int tmp=culculate(height,l,r);
        while(l<r){
            if(l+1<height.length-1 && culculate(height,l,r)<=culculate(height,l+1,r)){
                tmp=Math.max(culculate(height,l+1,r),tmp);
            }
            if(r-1>=0 && culculate(height,l,r)<=culculate(height,l,r-1)){
                tmp=Math.max(culculate(height,l,r-1),tmp);
                r--;
            }
            l++;
        }
        return tmp;
    }

    public int culculate(int[] height,int l,int r){
        int x=r-l;
        int ich=Math.min(height[l],height[r]);
        return x*ich;
    }
}
-----------------------------------------------------------------正解
public class Solution {
    public int maxArea(int[] height) {
        int l = 0, r = height.length - 1;
        int ans = 0;
        while (l < r) {
            int area = Math.min(height[l], height[r]) * (r - l);
            ans = Math.max(ans, area);
            if (height[l] <= height[r]) {
                ++l;
            }
            else {
                --r;
            }
        }
        return ans;
    }
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/container-with-most-water/solutions/207215/sheng-zui-duo-shui-de-rong-qi-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

三、写这个的原因

也许对教学以

及初学者有帮助


总结

从最后一次代码来看,我目前的水平还处于if-else的水平,改错方法属于增加if-else限制来补充逻辑不够。匿名函数和新特性都不会,这是需要加强的地方。

相关推荐
呃呃本1 小时前
算法题(回溯)
算法
刀法如飞1 小时前
Rust数组去重的20种实现方式,AI时代用不同思路解决问题
人工智能·算法·ai编程
yxc_inspire1 小时前
25年CCPC福建邀请赛补题
学习·算法
Raink老师1 小时前
用100道题拿下你的算法面试(链表篇-4):合并 K 个有序链表
算法·链表·面试
Liangwei Lin2 小时前
LeetCode 20. 有效的括号
算法
IronMurphy2 小时前
【算法四十四】322. 零钱兑换
算法
凯瑟琳.奥古斯特2 小时前
力扣2760 C++滑动窗口解法
数据结构·c++·算法·leetcode·职场和发展
Hesionberger2 小时前
LeetCode96: 不同的二叉搜索树(多解)
算法
_深海凉_2 小时前
LeetCode热题100-不同路径
算法·leetcode·职场和发展