前端刷题路-Day94:字母大小写全排列(题号784)

515 阅读3分钟

这是我参与8月更文挑战的第28天,活动详情查看:8月更文挑战

字母大小写全排列(题号784)

题目

给定一个字符串S,通过将字符串S中的每个字母转变大小写,我们可以获得一个新的字符串。返回所有可能得到的字符串集合。

示例:

输入:S = "a1b2"
输出:["a1b2", "a1B2", "A1b2", "A1B2"]

输入:S = "3z4"
输出:["3z4", "3Z4"]

输入:S = "12345"
输出:["12345"]

提示:

  • S 的长度不超过12
  • S 仅由数字和字母组成。

链接

leetcode-cn.com/problems/le…

解释

这题啊,这题是经典排列组合

类似的题目其实之前有做过,这里就当作巩固练习吧,熟能生巧。

首先,排列组合就是要找出所有的可能性,那如何找出所有的可能性?

很容易想到的就是从第一个字符开始处理,一点点累加字符串,在累加的过程中处理数字和字母不同的情况,再分别做对应的处理。

照着这个思路来说可能会有几个问题:

  1. 如何一点点处理?

    这里先说说迭代的思路,搞一个数组,它叫res,初始化值是一个空字符串,也就是''

    接下来从字符串的第一个位置开始遍历,遇到新的位置就循环res内所有的元素,在每个元素后面添加新的字符,有肯能是数字,也有可能是字母

    如果是数字操作十分简单,给每个元素后面添加就好了

    如果是字母则分别添加字母的大小写两种状态

    也就是说遇到数字,res的长度不会变,遇到字母res的长度翻倍,籍此完成遍历即可拿到最后的所有情况

  2. 如何区分字母和数字?

    这里笔者使用的是Number.isIntegerAPI,可以之间判断出是不是数字,如果不是自然就是字母了,因为题目说了:

    S 仅由数字和字母组成。

    但还有另外一种方法,利用charCodeAtAPI来判断,大写字母的区间应该是65到90,小写字母的区间是97到122,如果不在这个区间内的自然是数字了,或者也可以利用数字的区间来进行判断,都是可以的

  3. 如何确定字母的大小写?

    这个笔者每想出来判断的方法,于是很简单的使用了toUpperCasetoLowerCase这两个API,强行转化成大写和小写,不做任何判断

    但其实还有另外一种放啊,用异或运算符^好像可以直接进行转化,这个笔者就不是很清楚了,感兴趣的同学可以去看看

解决完这些问题后代码应该也就出来了。

除去迭代的方法后还有类似的递归操作,整体操作保持不变,将while替换成递归函数即可。

当然,这只是官方推荐的第一种解法,后续的两种解法笔者是真的看不太懂,直接放弃,具体的链接会放在更好的解法这一标题内,感兴趣的同学可以点进去看看。

自己的答案(迭代)

var letterCasePermutation = function(s) {
  const res = ['']
  for (let i = 0; i < s.length; i++) {
    const len = res.length
    const item = s.charAt(i)
    for (let j = 0; j < len; j++) {
      if (Number.isInteger(+item)) {
        res[j] = res[j] + item
      } else {
        res.push(res[j] + item.toUpperCase())
        res[j] = res[j] + item.toLowerCase()  
      }
    }
  }
  return res
};

整体思路和解释中说的别无二异,需要注意的可能就是这行代码了:

const len = res.length

为什么要把这个len提取出来?原因很简单,如果不提取出来,在遇到字母的情况就会出现无限循环了,因为遇到字母需要往res中添加字符串,这样res的长度会不断增加,永远无法走到尽头

所以这里需要提前记录下当前数组的长度,遍历到指定位置就停止,后续都是新增的字符串,不用管它。

自己的答案(递归)

var letterCasePermutation = function(s) {
  const res = []
  function DFS(i, str) {
    if (i === s.length) {
      return res.push(str)
    }
    const item = s.charAt(i)
    if (Number.isInteger(+item)) {
      DFS(i + 1, str + item)
    } else {
      DFS(i + 1, str + item.toLowerCase())
      DFS(i + 1, str + item.toUpperCase())
    }
  }
  DFS(0, '')
  return res
};

递归的判断啊,处理条件啥的都和迭代一样,新增的内容就是递归函数开头的终止条件,这个终止条件也很好理解,就是遍历完了就停止,这里利用字符串的长度来进行判断,其实如果s.charAt()''也代表递归到头了,用这个条件也是可以的。

其它的就没啥了,基础的递归操作

更好的方法

这块其实有两种解法

  • 二分掩码
  • 内置函数库

二分掩码利用比特符来进行操作 ,而内置函数库好像是用什么笛卡尔积来算,超纲了超纲了,有兴趣的同学可以点击这里查看官方答案~



PS:想查看往期文章和题目可以点击下面的链接:

这里是按照日期分类的👇

前端刷题路-目录(日期分类)

经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇

前端刷题路-目录(题型分类)