leetCode之Hash相关

首页目录 点击查看

第一题:

  • 难度:简单
  • 题目: 1.两数之和
    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
    你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

解题思路

我首先想到遍历数组两次的方法,找到num[j] = traget - num[i],保存后输出两个index.

我的答案

  • 两个for循环
        var twoSum = function (nums, target) {
            for (let i = 0; i <= nums.length - 1; i++) {
                for (let j = i + 1; j <= nums.length - 1; j++) {
                    if (nums[i] === target - nums[j]) {
                        return [ i, j]
                        break
                    }
                }
            }
        };
  • 时间复杂度:O(N2)
  • 空间复杂度: O(N)
    这明显不是最好的解决方案,就凭这两个for循环就很拉胯


    image.png

当然我也想出了另外一种方案,只需要一个for循环,用一个对象角标来保存目标数值: 这种方法从时间复杂度上只需要O(N)

        var twoSum = function (nums, target) {
            let useNum = {}
            for (let i = 0; i <= nums.length - 1; i++) {
                const currentNum = nums[i];
                const targetNum = target - currentNum;
                const targetIndex = useNum[targetNum]
                if (targetIndex !== undefined) {
                    return [targetIndex, i]
                    break
                }
                useNum[currentNum] = i
            }
        };
  • 时间复杂度:O(N)
  • 空间复杂度: O(N)


    结果

第二题

  • 难度:中等
  • 题目:763. 划分字母区间
    字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一个字母只会出现在其中的一个片段。返回一个表示每个字符串片段的长度的列表。

示例

输入:S = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca", "defegde", "hijhklij"。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少。

解题思路

  • 这道题虽然标签是贪心算法和双指针,想了一下还是只能想出用hash处理。所以这里把他放到hash相关来

我的答案

var partitionLabels = function (S) {
    let map = {}
    let arr = []
    let start = 0
    for (let i = 0; i <= S.length - 1; i++) {
        map[S[i]] = i;
    }
    let splitIndex = 0;
    for (let i = 0; i <= S.length; i++) {
        let lastIndex = map[S[i]];
        splitIndex = Math.max(splitIndex, lastIndex);
        if (i === splitIndex) {
            arr.push(i - start + 1);
            start = i + 1
        }
    }
    return arr
};
image.png

第三题

  • 难度:中等
  • 题目:49. 字母异位词分组
    给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。

示例

输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]

解题思路

  • 这道题需要把每个单独的字符串进行排序然后用map对象hash存储,如果相同的则都放在数组里面,最后输出数组

我的答案

var groupAnagrams = function (strs) {
    let map = {};
    let array = []
    for (let i = 0; i <= strs.length - 1; i++) {
        let sortStr = strs[i].split("").sort((a, b) => {
            return a > b ? 1 : -1
        }).join("")
        !map[sortStr] && (map[sortStr] = []);
        map[sortStr].push(strs[i])
    }
    for (let i in map) {
        array.push(map[i])
    }
    return array
};
image.png

第四题

  • 难度:简单
  • 题目:242. 有效的字母异位词
    给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例

输入: s = "anagram", t = "nagaram"
输出: true

输入: s = "rat", t = "car"
输出: false

解题思路

  • 这道题最简单的解法是把两个字符排序然后作比较,但是性能不太好,看了题解,而且这道题本来是用hash来做,前面那样就不算hash解法,所以有了第二个解法。

我的答案

  • 排序
        var isAnagram = function (s, t) {
            let sStr = s.split("").sort((a, b) => {
                return a > b ? 1 : -1
            }).join("");
            let tStr = t.split("").sort((a, b) => {
                return a > b ? 1 : -1
            }).join("");
            return sStr === tStr
        };
image.png
  • hash
        var isAnagram = function (s, t) {
            if (s.length !== t.length) {
                return false
            }
            let hash = new Array(26).fill(0);
            let codeA = "a".charCodeAt()
            for (let i = 0; i <= s.length - 1; i++) {
                hash[s.charCodeAt(i) - codeA]++;
                hash[t.charCodeAt(i) - codeA]--;
            }
            for (let i in hash) {
                if (hash[i]) {
                    return false
                }
            }
            return true
        };
image.png

第五题

  • 难度:简单
  • 题目:204. 计数质数
    统计所有小于非负整数 n 的质数的数量。

示例

输入:n = 10
输出:4
解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。

输入:n = 0
输出:0

解题思路

  • 这道题我能想到的是暴力算法,但是暴力算法直接超时了,所以得对暴力遍历进行优化,比如对于偶数直接跳过即可。但这明显不是最优解,时间都达到500多MS了,只是内存占用较少,看了题解发现了厄拉多塞筛法,这个方法非常高效。


    image.png

    对此,我们可以声明一个长度为最大限制数的布尔数组。用布尔值来区别筛选出的数和质数。

我的答案

        var countPrimes = function (n) {
            if (n < 3) {
                return 0
            }
            let num = 1;
            for (let i = 3; i <= n - 1; i++) {
                if (i % 2 == 0)      //过滤掉偶数,2 因为默认num就是1了所以也算在其中了。
                    continue;;
                let flag = true
                for (let j = 3; j * j <= i; j += 2) {
                    if (i % j === 0) {
                        flag = false
                        break;
                    }
                }
                if (flag) {
                    num += 1
                }
            }
            return num
        };
image.png
  • 厄拉多塞筛法
        var countPrimes = function (n) {
            let num = 0;
            let map = new Array(n).fill(false);
            for (let i = 2; i <= n - 1; i++) {
                if (!map[i]) {
                    num += 1;
                    for (let j = i + i; j <= n - 1; j += i) {
                        map[j] = true
                    }
                }
            }
            return num
        }
image.png

第六题

  • 难度:中等
  • 题目:299. 猜数字游戏
    你在和朋友一起玩 猜数字(Bulls and Cows)游戏,该游戏规则如下:
    你写出一个秘密数字,并请朋友猜这个数字是多少。
    朋友每猜测一次,你就会给他一个提示,告诉他的猜测数字中有多少位属于数字和确切位置都猜对了(称为“Bulls”, 公牛),有多少位属于数字猜对了但是位置不对(称为“Cows”, 奶牛)。
    朋友根据提示继续猜,直到猜出秘密数字。
    请写出一个根据秘密数字和朋友的猜测数返回提示的函数,返回字符串的格式为 xAyB ,x 和 y 都是数字,A 表示公牛,用 B 表示奶牛。
    xA 表示有 x 位数字出现在秘密数字中,且位置都与秘密数字一致。
    yB 表示有 y 位数字出现在秘密数字中,但位置与秘密数字不一致。
    请注意秘密数字和朋友的猜测数都可能含有重复数字,每位数字只能统计一次。

示例

输入: secret = "1807", guess = "7810"
输出: "1A3B"
解释: 1 公牛和 3 奶牛。公牛是 8,奶牛是 0, 1 和 7。

输入: secret = "1123", guess = "0111"
输出: "1A1B"
解释: 朋友猜测数中的第一个 1 是公牛,第二个或第三个 1 可被视为奶牛。

解题思路

  • 这道题公牛很好判断,一个for循环相同位置相等的即为公牛,奶牛比较麻烦,就需要两个map对象来存储当前出现的数字次数,最后比较两者之间相同的数字最少出现的次数就为奶牛。

我的答案

var getHint = function (secret, guess) {
    let ANum = 0;
    let BNum = 0;
    let mapS = {};
    let mapG = {}
    for (let i = 0; i <= secret.length - 1; i++) {
        if (secret[i] === guess[i]) {
            ANum += 1
        } else {
            !mapS[secret[i]] && (mapS[secret[i]] = 0);
            !mapG[guess[i]] && (mapG[guess[i]] = 0);
            mapS[secret[i]] += 1;
            mapG[guess[i]] += 1;
        }
    }
    for (let i in mapG) {
        if (mapS[i]) {
            BNum += Math.min(mapS[i], mapG[i])
        }
    }
    return ANum + "A" + BNum + "B"
};
image.png

第七题

  • 难度:中等
  • 题目: 554. 砖墙
    你的面前有一堵矩形的、由多行砖块组成的砖墙。 这些砖块高度相同但是宽度不同。你现在要画一条自顶向下的、穿过最少砖块的垂线。
    砖墙由行的列表表示。 每一行都是一个代表从左至右每块砖的宽度的整数列表。
    如果你画的线只是从砖块的边缘经过,就不算穿过这块砖。你需要找出怎样画才能使这条线穿过的砖块数量最少,并且返回穿过的砖块数量。
    你不能沿着墙的两个垂直边缘之一画线,这样显然是没有穿过一块砖的。

示例

输入: [[1,2,2,1],
      [3,1,2],
      [1,3,2],
      [2,4],
      [3,1,2],
      [1,3,1,1]]

输出: 2

解释: 
![image.png](https://upload-images.jianshu.io/upload_images/2669301-0094d2db4bc94c64.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

解题思路

  • 这道题很简单,只需要依次把每一行的数加起来,然后统计每一行某个和出现的次数,最多的那个数字就是没穿过的,穿过的就是数组长度减去出现最多的数字。

我的答案

var leastBricks = function (wall) {
    let map = {}
    let max = 0
    for (let i = 0; i <= wall.length - 1; i++) {
        let sum = 0
        for (let j = 0; j < wall[i].length - 1; j++) {
            sum += wall[i][j]
            !map[sum] && (map[sum] = 0);
            map[sum] += 1
            max = Math.max(map[sum], max)
        }
    }
    return wall.length - max
};
image.png

第八题

  • 难度:中等
  • 题目:974. 和可被 K 整除的子数组
    给定一个整数数组 A,返回其中元素之和可被 K 整除的(连续、非空)子数组的数目。

示例

输入:A = [4,5,0,-2,-3,1], K = 5
输出:7
解释:
有 7 个子数组满足其元素之和可被 K = 5 整除:
[4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3], [0], [0, -2, -3], [-2, -3]

解题思路

  • 这里只需要每个数组元素的和是5的倍数就可以,但是可能会出现0的情况,所以就在加一个5就可以把0的情况包含进去,于是...

我的答案

var subarraysDivByK = function (A, K) {
    let sum = 0;
    let result = 0;
    let map = new Array(K).fill(0)
    for (let i = 0; i <= A.length - 1; i++) {
        sum += A[i];
        let num = (sum % K + K) % K
        if (num === 0) result++
        result += map[num]
        map[num] += 1;
    }
    return result
};

image.png](https://upload-images.jianshu.io/upload_images/2669301-47341fe1aa9fbeb5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352