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

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

文章目录


前言

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


一、哈希

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限制来补充逻辑不够。匿名函数和新特性都不会,这是需要加强的地方。

相关推荐
CS创新实验室5 小时前
算法、齿轮与硅基大脑:数值计算发展简史
人工智能·算法·数值计算
海石6 小时前
1563分的简单题,可能就简单在能被暴力AC
算法·leetcode
海石7 小时前
1400分的dp汗流浃背之【交替子数组计数】
算法·leetcode
奋发向前wcx7 小时前
P2590 树的统计 题目解析
数据结构·算法·深度优先
imbackneverdie8 小时前
AI4S不止于分子药物:以MedPeer为代表的科研基建打开产业新增量
大数据·人工智能·算法·aigc·科研·学术·ai 4s
额鹅恶饿呃9 小时前
C语言中的数据结构和变量
c语言·数据结构·算法
运行时记录10 小时前
prompt-optimizer skill
算法
万法若空10 小时前
【数据结构-哈希表】哈希表原理
数据结构·算法·散列表
退休倒计时10 小时前
【每日一题】LeetCode 437. 路径总和 III TypeScript
算法·leetcode·typescript
学逆向的11 小时前
汇编——内存
开发语言·汇编·算法·网络安全