leetcode刷题记录
  • Leetcode刷题记录
  • 191 - 227 基本计算器2
  • 48 - 第二高的薪水
  • 226 - 494 目标和
  • 76 - 各位相加
  • 56 - 第十行
  • 196 - 328 奇偶链表
  • 106 - 485最大连续1的个数
  • 168 - 240 搜索二维矩阵2 - 001
  • 55 - 有效电话号码
  • 2 TOW SUM Ⅱ
  • 149 - 213 打家劫舍2
  • 91 - 有效的完全平方数
  • 59 - 198 打家劫舍
  • 166 - 92 反转链表2
  • 110 - 581 最短无序连续子数组
  • 197 - 454 四数相加2
  • 75 - 二叉树的所有路径
  • 41 - 最小栈
  • 27 - 最小差值
  • 177 - 337 打家劫舍3
  • 228 - 994 腐烂的橘子
  • 71 - 用栈实现队列
  • 30 - 将有序数组转换为二叉搜索树
  • 143 - 89 格雷编码
  • 184 - 152 乘积最大子序列
  • 221 - 354 俄罗斯套娃信封问题
  • 124 - 2 两数相加
  • 205 - 287 寻找重复数
  • 83 - 猜数字游戏
  • 25 - 对称二叉树
  • 90 - 两个数组的交集2
  • 163 - 877 石子游戏
  • 123 - 617 合并二叉树
  • 227 - 377 组合总和 Ⅳ
  • 144 - 146 LRU缓存机制
  • 18 - 加一
  • 145 - 215 数组中第k个最大元素
  • 65 - 存在重复元素
  • 17 - 最后一个单词的长度
  • 69 - 2的幂
  • 133 - 47 全排列2
  • 161 - 322 零钱兑换
  • 200 - 297 二叉树的序列化和反序列化
  • 152 - 63 不同路径2
  • 210 - 279 完全平方数
  • 154 - 264 丑数2
  • 183 - 212 单词搜索2
  • 22 - 删除排序链表中的重复元素
  • 100 - 左叶子之和
  • 128 - 16 最接近的三数之和
  • 204 - 162 寻找峰值
  • 190 - 239 滑动窗口最大值
  • 79 - 第一个错误版本
  • 178 - 52 n皇后2
  • 131 - 415 字符串相加
  • 8-最长公共前缀
  • 5-整数反转Reverse Integer
  • 159 - 120 三角形最小路径和
  • 64 - 反转链表
  • 21 - 爬楼梯
  • 36 - 买卖股票的最佳时机
  • 188 - 378 有序矩阵中第k小的元素
  • 135 - 54 螺旋矩阵
  • 24 - 相同的树
  • 33 - 路径总和
  • 202 - 179 最大数
  • 142 - 40 组合总和2
  • 104 - 414第三大的数
  • 180 - 140 单词拆分2
  • 129 - 33 搜索旋转排序数组
  • 225 - 474 一和零
  • 84 - 区域和检索- 数组不可变
  • 74 - 有效的字母异位词
  • 86 - 4的幂
  • 34 - 杨辉三角
  • 138 - 62 不同路径
  • 98 - 第n个数字
  • 85 - 3的幂
  • 49 - 超过经理收入的员工
  • 116 - 1025 除数博弈
  • 31 - 平衡二叉树
  • 97 - 判断子序列
  • 73 - 删除列表中的节点
  • 3-Two Sum IV - Input is a BST
  • 15 - 报数
  • 89 - 两个数组的交集
  • 167 - 74 搜索二维矩阵 - 001
  • 187 - 295 数据流的中位数
  • 164 - 72 编辑距离
  • 194 - 150 逆波兰表达式求值
  • 115 - 665 非递减数列
  • 81 - 单词规律
  • 139 - 78 子集
  • 150 - 148 排序链表
  • 140 - 90 子集2
  • 136 - 59 螺旋矩阵2
  • 16 - 最大子序和
  • 19 - 二进制求和
  • 12 - 移除元素
  • 112 - 628 三个数的最大乘积
  • 51 - 从不订购的客户
  • 39 - 只出现一次的数字
  • 189 - 347 前k个高频元素
  • 181 - 208 实现前缀树Trie
  • 35 - 杨辉三角2
  • 209 - 128 最长连续序列
  • 217 - 134 加油站
  • 147 - 230 二叉树搜索树中第k小的元素
  • 207 - 395 至少有K个重复字符的最长子串
  • git自动提交脚本
  • 212 - 127 单词接龙
  • 214 - 207 课程表
  • 117 - 661 图片平滑器
  • 186 - 334 递增的三元子序列
  • 105 - 448找到数组中消失的数字
  • 43 - excel表列名称
  • 113 - 643 子数组最大平均数1
  • 63 - 同构字符串
  • 7-罗马数字转整数
  • 195 - 138 复制带随机指针的链表
  • 107 - 532数组中的k-diff数对
  • 58 - 上升的温度
  • 141 - 39 组合总和
  • 182 - 79 单词搜索
  • 101 - 数字转换为16进制数
  • 125 - 5 最长回文子串
  • 23 - 合并两个有序数组
  • 40 - 环形链表
  • 95 - 字符串中的第一个唯一字符
  • 114 - 746使用最小花费爬楼梯
  • 37 - 买卖股票的最佳时机2
  • 132 - 46 全排列
  • 29 - 二叉树的层次遍历2
  • 77 - 丑数
  • 66 - 存在重复元素2
  • 68 - 翻转二叉树
  • 137 - 61 旋转链表
  • 60 - 快乐数
  • 54 - 位1的个数
  • 93 - 猜数字大小
  • 11 - 删除排序数组中的重复项
  • 134 - 51 N皇后
  • 99 - 二进制手表
  • 215 - 210 课程表 II
  • 224 - 518 零钱兑换 II
  • 127 - 11 盛最多水的容器
  • leetcode笔记
  • 4-3sum
  • 50 - 查找重复的电子邮箱
  • 176 - 621 任务调度器
  • 103 - fizz buzz
  • 220 - 188 买卖股票的最佳时机 IV
  • 82 - Nim游戏
  • 213 - 200 岛屿数量
  • 72 - 二叉树的最近公共祖先
  • 87 - 反转字符串
  • 78 - 缺失数字
  • 118 - 437 路径综合3
  • 121 - 538 把二叉树转换为累加树
  • 20 - x的平方根
  • 126 - 8 字符串转换整数
  • 157 - 464 我能赢吗
  • 158 - 42 接雨水
  • 80 - 移动零
  • 122 - 543 二叉树的直径
  • 199 - 380 常数时间插入、删除和获取随机元素
  • 背包九讲
  • 9-有效的括号
  • 47 - 组合两个表
  • 1 两数之和(Two Sum)
  • 62 - 计数质数
  • 88 - 反转字符串中的元音字母
  • 14 - 搜索插入位置
  • 28 - 二叉树层次遍历1
  • 119 - 461 汉明距离
  • 70 - 回文链表
  • 32 - 二叉树的最小深度
  • 46 - 阶乘后的零
  • 120 - 557 反转字符串中的单词3
  • 170 - 154 寻找旋转排序数组中的最小值2 - 006
  • 57 - 删除重复的电子邮箱
  • 53 - 颠倒二进制位
  • 223 - 132 分割回文串
  • 146 - 238 除自身外数组的乘积
  • 109 - 566重塑矩阵
  • 45 - excel表序列号
  • 174 - 1004 最大连续1的个数3
  • 171 - 替换空格 - 002
  • 179 - 131 分割回文串
  • 198 - 18 四数之和
  • 6-回文数
  • 52 - 旋转数组
  • 172 - 151 翻转字符串里面的单词 - 044
  • 192 - 224 基本计算器
  • 173 - 567 字符串的排列 027
  • 208 - 124 二叉树中的最大路径和
  • 13 - 实现strStr()
  • 42 - 相交链表
  • 169 - 153 寻找旋转排序数组最小值 - 006
  • 108 - 561数组拆分
  • 211 - 329 矩阵中的最长递增路径
  • 153 - 64 最小路径和
  • 225 - 416 分割等和子集
  • 222 - 486 预测赢家
  • 203 - 324 摆动排序2
  • 175 - 260 只出现一次的数字3 - 040
  • 155 - 96 不同的二叉搜索树
  • 165 - 887 鸡蛋掉落
  • 102 - 最长回文串
  • 193 - 341 扁平化嵌套列表迭代器
  • 10 - 合并两个有序链表
  • 162 - 300 最长上升子序列
  • 160 - 139 单词拆分
  • 151 - 236 二叉树的最近公共祖先
  • 44 - 求众数
  • 185 - 384 打乱数组
  • 216 - 149 直线上最多的点数
  • 61 - 移除链表元素
  • 218 - 91 解码方法
  • 67 - 用队列实现栈
  • 219 - 123 买卖股票的最佳时机
  • 比赛
  • 92 - 两整数之和
  • 130 - 43 字符串相乘
  • 96 - 找不同
  • 111 - 605种花问题
  • 201 - 218 天际线问题
  • 26 - 二叉树的最大深度
  • 206 - 315 计算右侧小于当前元素的个数
  • 94 - 赎金信
  • 38 - 验证回文串
  • 148 - 142 环形链表2
  • 156 - 95 不同的二叉搜索树2
Powered by GitBook
On this page
  • 题目
  • 解答
  • 排序
  • 哈希表
  • 哈希表的第二种解法
  • 使用数组

Was this helpful?

74 - 有效的字母异位词

题目

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例 1:

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

示例 2:

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

说明: 你可以假设字符串只包含小写字母。

进阶: 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?

解答

就是判断一下,字母是不是还是那些字母?

感觉可以一个个拿出来对比下,如果有,就删掉原来的字符串的字母

var isAnagram = function (s, t) {
  if (s.length !== t.length) {
    return false
  }
  for (const item of t) {
    if (s.indexOf(item) !== -1) {
      s = s.replace(item, "")
    }
  }
  return s === ""
};

Runtime: 284 ms, faster than 5.04% of JavaScript online submissions for Valid Anagram.

Memory Usage: 49.7 MB, less than 6.12% of JavaScript online submissions for Valid Anagram.

replace后的结果需要再存到s里面,因为没做这个卡了半天😂😂

不过这个方法效率极慢

func isAnagram(s string, t string) bool {
    if len(s) != len(t) {
        return false
    }
    for _, elem := range t {
        if strings.Contains(s, string(elem)) {
            s = strings.Replace(s, string(elem), "", 1)
        }
    }
    return s == ""
}

Runtime: 284 ms, faster than 5.04% of JavaScript online submissions for Valid Anagram.

Memory Usage: 49.7 MB, less than 6.12% of JavaScript online submissions for Valid Anagram.

go的话需要用strings的包,不过效率也太慢了吧。。怕是这种算法不够好

排序

排序并一一验证,感觉很酷😂咋就没想到呢。

var isAnagram = function (s, t) {
  if (s.length !== t.length) {
    return false
  }
  s = s.split('').sort().join('')
  t = t.split('').sort().join('')
  return s === t
};

Runtime: 100 ms, faster than 36.20% of JavaScript online submissions for Valid Anagram.

Memory Usage: 38.2 MB, less than 30.61% of JavaScript online submissions for Valid Anagram.

感觉稍微快了一点

go就没这么方便了。。写得很僵硬

func isAnagram(s string, t string) bool {
    if len(s) != len(t) {
        return false
    }
    sl := []byte(s)
    tl := []byte(t)
    sort.Slice(sl, func(i, j int) bool {
        return sl[i] < sl[j]
    })
    sort.Slice(tl, func(i, j int) bool {
        return tl[i] < tl[j]
    })
    for i, elem := range sl {
        if elem != tl[i] {
            return false
        }
    }
    return true
}

Runtime: 8 ms, faster than 56.80% of Go online submissions for Valid Anagram.

Memory Usage: 3.2 MB, less than 16.67% of Go online submissions for Valid Anagram.

字符串怎么排序呢?不管怎么做都要变成切片,不然没法排序。

而go中字符串,是作为ascii码存的,也就是说看起来是字母,其实拿到手之后是数字

而字符串转切片,是不能b := []string(s)这样转的。不然:

sl := []string{"a", "v", "b", "c",.....}
sort.Sort(sort.StringSlice(sl))

就直接排序完了

我查到,只能把字符串转成byte或uint8sl := []byte(s)这样

排序这个,就只能手写一个sort.Slice函数,用第二个参数写一个函数来返回排序的方法

然后还需要最后循环对比一下数组

对比一下python,只需要一行😂😂

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        return sorted(s) == sorted(t)

Runtime: 60 ms, faster than 60.68% of Python3 online submissions for Valid Anagram.

Memory Usage: 14.7 MB, less than 6.25% of Python3 online submissions for Valid Anagram.

虽然没go那么高效,但起码多保留了几根我的头发😂😂

js也有一行解:

var isAnagram = function(s, t) {
    return s.split('').sort().join('') == t.split('').sort().join('')
};

Runtime: 104 ms, faster than 30.24% of JavaScript online submissions for Valid Anagram.

Memory Usage: 38.5 MB, less than 18.37% of JavaScript online submissions for Valid Anagram.

var isAnagram = function(s, t) {
    return [...t].sort().join('') === [...s].sort().join('');
};

Runtime: 112 ms, faster than 16.70% of JavaScript online submissions for Valid Anagram.

Memory Usage: 42 MB, less than 6.12% of JavaScript online submissions for Valid Anagram.

就是似乎不怎么高效

哈希表

一开始的想法就是哈希表,但不知道怎么判断字母这个key,对应的value是否都为0,难不成要遍历一遍吗

题解:是的。

好吧。。

func isAnagram(s string, t string) bool {
    if len(s) != len(t) {
        return false
    }
    count := make(map[uint8]int)
    for i := 0; i < len(s); i++ {
        count[s[i]]++
        count[t[i]]--
    }
    for _, elem := range count {
        if elem != 0 {
            return false
        }
    }
    return true
}

Runtime: 8 ms, faster than 56.80% of Go online submissions for Valid Anagram.

Memory Usage: 3 MB, less than 83.33% of Go online submissions for Valid Anagram.

不知道为什么题解里面存的key,是[s.charAt(i) - 'a'],实测了一下,减不减a成本是一样的

go里面有一点很僵硬,字符串里面存的是rune,即int32。而经过for..range之后,取出来的elem,却是一个uint8,也就是一个byte

s := "abac"
for i, elem := range s {
  fmt.Println("elem", fmt.Sprintf("%T", elem))  // int32
  fmt.Println("i", fmt.Sprintf("%T", s[i]))    // uint8
}

所以要存map,只能统一用i来一起取,不然map的类型都就没法定义

感觉这个和取字符串的元素一样,很反直觉,为啥取出来的时候还要转换一下类型?也许和go的存储方式有关?

作者:zit-3

var isAnagram = function (s, t) {
  if (s.length !== t.length) {
    return false;
  }
  const obj = {};
  for (let i = 0; i < s.length; i++) {
    obj[s[i]] ? obj[s[i]]++ : (obj[s[i]] = 1)
    obj[t[i]] ? obj[t[i]]-- : (obj[t[i]] = -1)
  }
  return Object.keys(obj).every(item => obj[item] === 0);
};

Runtime: 68 ms, faster than 80.40% of JavaScript online submissions for Valid Anagram.

Memory Usage: 36.2 MB, less than 59.18% of JavaScript online submissions for Valid Anagram.

不知道为啥题解中是用charAt(i),实测和s[i]是一样的,而且用s[i]效率更高。。

charAt(i)的意思是,i是一个index,返回这个index对应的元素。其实就和s[i]一样😂

也不知道js为啥要搞出这两个方法做同一件事。。

...
  for (let i = 0; i < s.length; i++) {
    obj[s.charAt(i)] ? obj[s.charAt(i)]++ : (obj[s.charAt(i)] = 1);
    obj[t.charAt(i)] ? obj[t.charAt(i)]-- : (obj[t.charAt(i)] = -1);
  }
...

Runtime: 80 ms, faster than 50.43% of JavaScript online submissions for Valid Anagram.

Memory Usage: 36.4 MB, less than 53.06% of JavaScript online submissions for Valid Anagram.

不过感觉这样不够高效,因为every可能和foreach或map一样,都一定要跑完全部元素。而我们只需要有一个false就可以退出了

var isAnagram = function (s, t) {
...
  for (const i in obj) {
    if (obj[i] != 0) {
      return false
    }
  }
  return true
};

Runtime: 60 ms, faster than 95.80% of JavaScript online submissions for Valid Anagram.

Memory Usage: 36.1 MB, less than 67.35% of JavaScript online submissions for Valid Anagram.

可以看到速度快了,占用内存也小了。

然后实测了一波,似乎every是有false就退出的😂

感觉js后面出来的骚操作,速度都没最简单的for循环要好,之前也遇到过哈哈😂

以前每次map都能略胜于obj,这次呢?

var isAnagram = function (s, t) {
  if (s.length !== t.length) {
    return false
  }
  let count = new Map()
  for (let i = 0; i < s.length; i++) {
    count.get(s[i]) ? count.set(s[i], count.get(s[i]) + 1) : count.set(s[i], 1)
    count.get(t[i]) ? count.set(t[i], count.get(t[i]) - 1) : count.set(t[i], -1)
  }
  for (const item of count) {
    if (item[1] != 0) {
      return false
    }
  }
  return true
};

Runtime: 76 ms, faster than 56.94% of JavaScript online submissions for Valid Anagram.

Memory Usage: 36.8 MB, less than 53.06% of JavaScript online submissions for Valid Anagram.

感觉不太行的亚子😂😂

  • in能取到数组的index,of能取到数组的内容

  • in能取到对象的key,但用of取不到value,反而会报错

换言之,数组底层也是类似于map的存咯,不过key就是其index?类似于。。

const array = {
  0:"a",
  1:"b"
}

那为啥用of就取不到obj的value呢?是设计的时候就规定死了,obj不可迭代?

  • of能取到map的内容,但in取出来的是undefined

所以map的存储类似于。。

const map = [
  ["a", 1],
  ["b", 2]
]

如果换算成obj的话,map还是。。

const map1 = {
  undefined: ["a", 1],
  undefined: ["b", 2]
}

这种感觉??可迭代没key的obj??

哈希表的第二种解法

先用s加,然后再用t减,如果有小于0的情况,就直接判false

var isAnagram = function (s, t) {
  if (s.length !== t.length) {
    return false;
  }
  const obj = {};
  for (let i = 0; i < s.length; i++) {
    obj[s[i]] ? obj[s[i]]++ : (obj[s[i]] = 1)
  }
  for (let i = 0; i < t.length; i++) {
    if (!obj[t[i]]) {
      return false
    }
    obj[t[i]]--
    if (obj[t[i]] < 0) {
      return false;
    }
  }
  return true
};

Runtime: 68 ms, faster than 80.26% of JavaScript online submissions for Valid Anagram.

Memory Usage: 36 MB, less than 77.55% of JavaScript online submissions for Valid Anagram.

如果t中有s没有的值,那么就直接变成false,或者如果有令其为0的值,也变成false

感觉每次都要判断两次,有点浪费,不过也想不到更好的方法了😂

用go写起来就简单一些,不用这么麻烦的判断了😂

func isAnagram(s string, t string) bool {
    if len(s) != len(t) {
        return false
    }
    count := make(map[uint8]int)
    for i := 0; i < len(s); i++ {
        count[s[i]]++
    }
    for i := 0; i < len(t); i++ {
        count[t[i]]--
        if count[t[i]] < 0 {
            return false
        }
    }
    return true
}

Runtime: 8 ms, faster than 57.14% of Go online submissions for Valid Anagram.

Memory Usage: 3 MB, less than 50.00% of Go online submissions for Valid Anagram.

使用数组

就是创建一个数组,一共26个格子,对应26个字母。如果s有就在那个位置+1,t就-1

func isAnagram(s string, t string) bool {
    if len(s) != len(t) {
        return false
    }
    m := make([]int, 26)
    for i := 0; i < len(s); i++ {
        m[s[i]-'a']++
    }
    for i := 0; i < len(s); i++ {
        m[t[i]-'a']--
        if m[t[i]-'a'] < 0 {
            return false
        }
    }
    return true
}

Runtime: 0 ms, faster than 100.00% of Go online submissions for Valid Anagram.

Memory Usage: 3 MB, less than 100.00% of Go online submissions for Valid Anagram.

哇塞。。速度超快!

那如果是用第一种做法呢?效果也一样吗?

func isAnagram(s string, t string) bool {
    if len(s) != len(t) {
        return false
    }
    m := make([]int, 26)
    for i := 0; i < len(s); i++ {
        m[s[i]-'a']++
        m[t[i]-'a']--
    }
    for _, elem := range m {
        if elem != 0 {
            return false
        }
    }
    return true
}

Runtime: 0 ms, faster than 100.00% of Go online submissions for Valid Anagram.

Memory Usage: 3 MB, less than 100.00% of Go online submissions for Valid Anagram.

好吧根本看不出差别。

js好像没啥办法,能创建固定大小的数组。

全填为0的方法,似乎是for循环最简单粗暴效率高了。

var isAnagram = function (s, t) {
  if (s.length !== t.length) {
    return false;
  }
  var m = [];
  for (var n = 0; n < 26; n++) {
    m[n] = 0
  }
  for (let i = 0; i < s.length; i++) {
    m[s[i].charCodeAt() - 97]++
  }
  for (let i = 0; i < t.length; i++) {
    m[t[i].charCodeAt() - 97]--
    if (m[t[i].charCodeAt() - 97] < 0) {
      return false;
    }
  }
  return true
};

Runtime: 60 ms, faster than 95.74% of JavaScript online submissions for Valid Anagram.

Memory Usage: 35.7 MB, less than 93.88% of JavaScript online submissions for Valid Anagram.

这个算法好像是速度最快的

js换算对应的ascii码,还需要用s[i].charCodeAt()转一下,这么说来go的直接rune相见,在某些情况下还是挺实用的吼😂😂

Previous84 - 区域和检索- 数组不可变Next86 - 4的幂

Last updated 5 years ago

Was this helpful?

js字符串转数组的一行解,还有:

链接:

Array.every()是用来,每个元素是否都满足某个条件。某个条件即括号里面的函数的返回值。都满足就最终返回true,不然返回false。

image-20190906221207742

关于for..of和for..in,感觉很有趣

image-20190906221859606
image-20190906224441898

但为了之后的++方便,需要

https://leetcode.com/problems/valid-anagram/discuss/310230/JS-1-line-solution
第二种方法
https://leetcode-cn.com/problems/valid-anagram/solution/js-jian-dan-xie-fa-by-zit-3/
检验一个数组里面
这两者的区别
把26个位置都填为0