算法练习-Day4-有效的字母异位词

题目:

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

示例 1:

ini 复制代码
输入: s = "anagram", t = "nagaram"
输出: true

示例 2:

ini 复制代码
输入: s = "rat", t = "car"
输出: false

提示:

  • 1 <= s.length, t.length <= 5 * 104
  • st 仅包含小写字母

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

解释:

  • 字母异位词(anagram)指的是两个字符串,长度相同,且每个字符出现的次数都一样,顺序可以不同。
  • car 和 car 两个字符串完全一样,当然每个字符出现的次数都一样,所以它们是字母异位词。

实现:

1. 这是我之前学python的时候做的

python 复制代码
class Solution(object):
    def isAnagram(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: bool
        """
        # 母异位词必须是两个长度相同的字符串
        if len(s) == len(t):
            for i in s:
                # 每个字符出现的次数都一样
                if i not in t or s.count(i) != t.count(i):
                    # 如果有t中的字符不存在s中的某一字符,或者数量不一样,就返回False
                    return False
            return True
        else:
            return False

2. 下面是我用JavaScript的实现

2.1 用ASII码实现

  • 之所以会想到使用ASII码来实现原因主要是提示里有一条:st 仅包含小写字母,这是我的逻辑,不一定正确,大家可以帮忙指出问题
  • 另外我想的是这两个字符串里面包含的字符是完全相同的(只是顺序不同罢了),所以只要这两个字符串所有的字符转成ASII码值,然后综合相等,就可以了
js 复制代码
/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function(s, t) {
    // 母异位词必须是两个长度相同的字符串
    if (s.length !== t.length) return false
    let sum1 = 0;
    let sum2 = 0;
    for (const char of s) {
        sum1 += char.charCodeAt();
    }
    for (const char of t) {
        sum2 += char.charCodeAt();
    }
    return sum1 === sum2
}

结果:

  • 两个示例都通过了
  • 但是有了反例:s ="ggii",t ="eekk"
  • 40 / 53 个通过的测试用例

2.2 用和python实现相同的方法

  • js没有直接统计一个字符在字符串中出现的次数的方法,我还去特意查了一下可以用str.split(char).length + 1来统计
  • 这里我犯了一个错误:我用了for...in来遍历字符串s了,注意:for...in遍历字符串只会遍历字符串的索引
js 复制代码
/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function(s, t) {
    if (s.length !== t.length) return false
    for (let char of s) {
        if (!t.includes(char) || s.split(char).length !== t.split(char).length) {
            return false
        }
    }
    return true
};

结果:

  • 两个示例都通过了
  • 但是当面对超长字符串时,超时了,直接给浏览器干崩溃了
  • 其实时间复杂度只是O(n^2)

2.3 Deepseek给2.2的优化版本

js 复制代码
var isAnagram = function(s, t) {
    if (s.length !== t.length) return false;
    
    const count = {};
    // 统计s的字符
    for (let char of s) {
        count[char] = (count[char] || 0) + 1;
    }
    // 验证t的字符
    for (let char of t) {
        if (!count[char]) return false;
        count[char]--;
    }
    return true;
};

结果

  • 通过率100%

复杂度对比

方法 时间复杂度 空间复杂度
原始实现 O(n²) O(n)(split创建临时数组)
优化实现 O(n) O(1)(因为字母表固定大小)

关键点:当处理字符串问题时,尽量避免在循环内使用includes()split()等O(n)操作。

2.4 结合排序实现

  • 这个我一开始就想到了,但是我觉的直接使用sort排序是不是就像我昨天使用indexOf一样,就是说,用方法的话,那还能叫算法吗
  • 但是,这是一种方法,leedCode通过率100%
js 复制代码
/**
* 时间复杂度O(n log n)
* split(): O(n)
* sort(): 通常O(n log n)(取决于JS引擎实现)
* join(): O(n)
**/
var isAnagram = function(s, t) {
    if (s.length !== t.length) return false;
    return s.split('').sort().join('') === t.split('').sort().join('');
};

// 下面是Deepseek给的优化版### (O(n)时间,O(1)空间)
var isAnagram = function(s, t) {
    if (s.length !== t.length) return false;
    
    const count = new Array(26).fill(0); // 因为题目说明只含小写字母
    
    for (let i = 0; i < s.length; i++) {
        count[s.charCodeAt(i) - 97]++; // 'a'.charCodeAt() = 97
        count[t.charCodeAt(i) - 97]--;
    }
    
    return count.every(v => v === 0);
};

2.5 Cursor推荐使用哈希表计数法

  • 这个我本来也不懂,但是仔细一看这个和2.3就是一种方法
  • 就是用一个对象记载字符char和出现的次数的映射
  • 我本来担心map[char]--;会不会为负数,我的担心是多余的,在他为负数之前,if (!map[char])就已经返回了
js 复制代码
var isAnagram = function(s, t) {
    if (s.length !== t.length) return false;
    const map = {};
    for (const char of s) {
        map[char] = (map[char] || 0) + 1;
    }
    for (const char of t) {
        if (!map[char]) return false;
        map[char]--;
    }
    return true;
};

总结:

有志者,事竟成,破釜沉舟,百万秦关终属楚; 苦心人,天不负,卧薪尝胆,三千越甲可吞吴。


虽然很简单的一个小算法题,但我也呕心沥血了,写完已经凌晨00:40了,望博友们给个支持!!!

相关推荐
一念&2 小时前
每日一个C语言知识:C 头文件
c语言·开发语言·算法
驭风少年君3 小时前
《搭建属于自己的网站之网页前端学习》基础入门
前端·学习
刘一说4 小时前
深入理解 Spring Boot 嵌入式 Web 容器:从原理到性能调优
前端·spring boot·firefox
你的人类朋友4 小时前
设计模式的原则有哪些?
前端·后端·设计模式
!执行5 小时前
Web3 前端与合约交互
前端·web3·1024程序员节
潘小安5 小时前
跟着 AI 学(二)- Quill 接入速通
前端
十里-5 小时前
在 Vue2 中为 Element-UI 的 el-dialog 添加拖拽功能
前端·vue.js·ui
shada5 小时前
从Google Chrome商店下载CRX文件
前端·chrome
Miraitowa_cheems5 小时前
LeetCode算法日记 - Day 88: 环绕字符串中唯一的子字符串
java·数据结构·算法·leetcode·深度优先·动态规划
左耳咚5 小时前
项目开发中从补码到精度丢失的陷阱
前端·javascript·面试