leetcode每天5题-Day12


之前刷题,遇到哈希的解法,就觉得很神奇。前几天遇到一道题,能想到用哈希解决,但还是不会写,今天特意练一下。
都是哈希的简单题

这两天突然想到, hash和map什么关系
hash的实质是一种算法,可以将其看成函数 f(),即有这样的关系: A=f(a)
map就是一个数据结构, key放值, value放值。当放入 value的内容是基础类型数据时,里面放的是值的本身,当放入的引用类型的时候,其中是地址,然后通过地址调用值。

参考👉这篇
HASH 与MAP 的区别

1.将找到的值乘以 2

leetcode2154. 将找到的值乘以 2
①排序

var findFinalValue = function(nums, original) {
    nums.sort((a,b)=>a-b);
    for(const num of nums){
        while(original==num){
            original=2*original;
        }
        
    }
    return original;
};

时间复杂度:O(nlogn),其中n为nums 的长度。排序的时间复杂度为O(nlogn),遍历更新original 的时间复杂度最多为O(n)
空间复杂度:O(logn),即为排序的栈空间开销。
②哈希表
用空间换时间

var findFinalValue = function(nums, original) {
    const set=new Set();
    for(let i=0;i<nums.length;i++){
        set.add(nums[i]);
    }
    while(set.has(original)){
        original*=2;
    }
    return original;
};

Map 和 Set 使用的区别和联系
js中的map和set

2.最常见的单词

leetcode819. 最常见的单词
题目: 给定一个段落 (paragraph) 和一个禁用单词列表 (banned)。返回出现次数最多,同时不在禁用列表中的单词。
题目保证至少有一个词不在禁用列表中,而且答案唯一。
禁用列表中的单词用小写字母表示,不含标点符号。段落中的单词不区分大小写。答案都是小写字母。
①哈希表+计数
为了高效检查单词是否被禁止,使用了集合Set对象

var mostCommonWord = function(paragraph, banned) {
    const len=paragraph.length;
    // 把禁用单词放进Set里
    const bannedSet=new Set();
    for(const word of banned){
        bannedSet.add(word);
    }

    // 记录某个单词出现的最大次数
    let maxCount=0;
    const maps=new Map();
    let sp='';

    for(let i=0;i<=len;i++){
        if(i<len&&isLetter(paragraph[i])){
            sp=sp+paragraph[i].toLowerCase();
        }else if(sp.length>0){
            if(!bannedSet.has(sp)){
                const map=(maps.get(sp)||0)+1;
                maps.set(sp,map);
                maxCount=Math.max(maxCount,map);
            }
            sp='';
        }
    }
    let ans="";
    for(const [word,map] of maps.entries()){
        if(map==maxCount){
            ans=word;
            break;
        }
    }
    return ans;
};
const isLetter=(word)=>{
    return (word>='a'&&word<='z')||(word>='A'&&word<='Z');
}

好复杂这个方法…
时间复杂度:O(n+m),其中n是段落paragraph的长度,m是禁用单词列表 banned的长度。遍历禁用单词列表一次将禁用单词存入哈希集合中需要O(m)的时间,遍历段落得到每个非禁用单词的计数需要O(n)的时间,遍历哈希表得到最常见的单词需要O(n)的时间。
空间复杂度:O(n+m),其中n是段落paragraph的长度,m是禁用单词列表 banned的长度。存储禁用单词的哈希集合需要O(m)的空间,记录每个单词的计数的哈希表需要O(n)的空间。
②Set+Map+split()
感觉这种方法就清晰明了很多:

var mostCommonWord = function(paragraph, banned) {
    const set=new Set();
    banned.forEach(ban => set.add(ban));
    let ans="";
    const map=new Map();
    // 切割单词时,用了js的split方法,
    // 该方法支持正则表达式,将连续的空格或标点符号作为分隔符,即可正确分割单词
    paragraph.split(/[!\?',;\.' ]+/).forEach(v =>{ //根据标点符号或空格分割成多个单词,转小写,计数
        if(v=="") return;
        v=v.toLocaleLowerCase();
        if(set.has(v)) return;
        map.set(v,map.has(v)?map.get(v)+1:1);
    });
    let maxCount=0;
    //  找次数最多的单词
    [...map.entries()].forEach(([k,v]) => {
        if(maxCount<v){
            maxCount=v;
            ans=k;
        }
    })
    return ans;
};

toLowerCase和toLocaleLowerCase()的区别

3.存在重复元素

217. 存在重复元素
题目: 给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false
①排序
对数组排序,然后判断相邻元素是否相等。

var containsDuplicate = function(nums) {
    nums.sort((a,b)=>a-b);
    for(let i=0;i<nums.length;i++){
        if(nums[i]==nums[i+1]){
            return true;
        }
    }
    return false;
};

时间复杂度:O(NlogN),其中N为数组的长度。需要对数组进行排序。
空间复杂度:O(logN),其中N为数组的长度。注意:这里应当考虑递归调用栈的深度。
②哈希表
不需要记录每个数字出现的次数,只要哈希表中已经存在该数字,返回true即可。

var containsDuplicate = function(nums) {
    const set=new Set();
    for(const num of nums){
        if(set.has(num)){
            return true;
        }
        set.add(num);
    }
    return false;
};

或者

var containsDuplicate = function(nums) {
    const map=new Map();
    for(const num of nums){
        if(map.has(num)){
            return true;
        }
        map.set(num,1);
    }
    return false;
};

时间复杂度:O(N),其中N为数组的长度。

空间复杂度:O(N),其中N为数组的长度。

4.存在重复元素II

219. 存在重复元素 II
题目: 给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 ij ,满足 nums[i] == nums[j]abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false
①哈希表
判断当前元素是否已在哈希表中,不在就添加到哈希表中;如果在,判断当前元素索引和哈希表中的索引差值,小于k时直接返回true,否则就用当前元素的索引覆盖上一个相同元素的索引值。
然后看了一下官方解法,发现跟官方解法的代码是一样的,思路也差不多。

var containsNearbyDuplicate = function(nums, k) {
    const map=new Map();
    for(let i=0;i<nums.length;i++){
        if(map.has(nums[i])){
            if(Math.abs(map.get(nums[i])-i)<=k){
                return true;
            }
        }
        map.set(nums[i],i);
    }
    return false;
};

时间复杂度:O(n),其中n是数组nums的长度。需要遍历数组一次,对于每个元素,哈希表的操作时间都是O(1)
空间复杂度:O(n),其中n是数组nums的长度。需要使用哈希表记录每个元素的最大下标,哈希表中的元素个数不会超过n
②滑动窗口+Set

var containsNearbyDuplicate = function(nums, k) {
    const set=new Set();
    for(let i=0;i<nums.length;i++){
        if(i>k){
            set.delete(nums[i-k-1]);
        } 
        if(set.has(nums[i])){
            return true;
        }
        set.add(nums[i]);
    }
    return false;
};

时间复杂度:O(n),其中n是数组nums的长度。需要遍历数组一次,对于每个元素,哈希集合的操作时间都是O(1)
空间复杂度:O(k),其中k是判断重复元素时允许的下标差的绝对值的最大值。需要使用哈希集合存储滑动窗口中的元素,任意时刻滑动窗口中的元素个数最多为k+1个。

5.同构字符串

205. 同构字符串-简单
题目: 给定两个字符串 st ,判断它们是否是同构的。
如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的。
每个出现的字符都应当映射到另一个字符,同时不改变字符的顺序。不同字符不能映射到同一个字符上,相同字符只能映射到同一个字符上,字符可以映射到自己本身。
①Set+Map
map中放s的元素及其映射到的t中的元素,set中放t的元素,防止出现不同元素映射到同一个元素的情况。

var isIsomorphic = function(s, t) {
    const map=new Map();
    const set=new Set();
    for(let i=0;i<s.length;i++){
        if(!map.has(s[i])){
        // 如果map中不存在s的当前字符且set中也不存在t的当前字符
            if(!set.has(t[i])){
                set.add(t[i]);
                map.set(s[i],t[i]);
            }else{
          // 如果map中不存在s的当前字符但set中存在t的当前字符,说明不同字符映射到了同个字符 直接返回false
                return false;
            }           
        }
        if(map.has(s[i])&&map.get(s[i])!==t[i]){
            return false;
        }
    }
    return true;
};

写了个题解,好像时第一次写题解…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值