前言
初始算法中的字符串部分挑选之后有几题值得记录的,这里拿出来说明记录一下。对于字符串的重点在于正则表达式的运用。
1.有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram"
输出: true
示例 2:
输入: s = "rat", t = "car"
输出: false
说明:
你可以假设字符串只包含小写字母。
进阶:
如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
这里我想到的解法是使用 map 存储 字符串 中字母出现的次数,字母异位词其实就是字母经过移位,但是字母出现的次数相同,这就可以判断了。
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var isAnagram = function(s, t) {
if (s.length !== t.length) {
return false;
}
var map = {};
for (let c of s) {
map[c] = map[c] + 1 || 1;
}
for (let c of t) {
if (typeof map[c] === "undefined" || map[c] === 0) {
return false;
} else {
map[c]--;
}
}
return true;
};
答案解法:使用正则表达式的全局匹配,每次都将一个字符串的首字母使用全局匹配在两个字符串中去掉,并且比较两个字符串的 长度是否相等 或者 两个字符串是否相等 来判断是否合法
// answer algorithm
/**
* 思路:
* 利用正则表达式,
* 不断地将两个字符串中出现的某个 字符全部去掉,
* 以此判断是否是字母异位词,
* 因为字母异位词中,出现的字母和次数都是一样的,只是顺序不同
*/
var isAnagram_answer = function(s, t) {
while (s !== t && s.length === t.length) {
if (s === t || s.length !== t.length) {
break;
}
var letter = new RegExp(s[0], "g");
s = s.replace(letter, "");
t = t.replace(letter, "");
}
return s === t;
};
2.报数
报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
1. 1
2. 11
3. 21
4. 1211
5. 111221
1 被读作 "one 1" ("一个一") , 即 11。
11 被读作 "two 1s" ("两个一"), 即 21。
21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。
注意:整数顺序将表示为一个字符串。
示例 1:
输入: 1
输出: "1"
示例 2:
输入: 4
输出: "1211"
题意给人的感觉有点懵逼,这里附加说明一下:
第一个开始是 '1',读作 1 个 1;
故 第二个就是 '11' ,读作 2 个 1;
第三个是 '21',读作 1 个 2,1 个 1;
所以第四个是'1211'即前一个的读作中数字的拼接是下一个的输出。
答案解法:
使用一个 二维数组 map ,记录的就是 相同数字 挨着出现的次数:
即 [数字出现的次数,数字]
如 [ [1,2], [1,1] ] 表示 "1 个 2,1 个 1",此时只需要遍历 str 即可
/**
* @param {number} n
* @return {string}
*/
var countAndSay = function(n) {
let str = '1';
while(n > 1) {
let buffle = str[0];
const map = [[1,buffle]];
// 从第二个字符串开始遍历
for(let i = 1;i < str.length;i++) {
if(str[i] === buffle) {
map[map.length - 1][0]++;
} else {
buffle = str[i];
map.push([1,buffle]);
}
}
str = '';
map.forEach((item,index) => {
str += (item[0] + '' + item[1]);
});
n--;
}
return str;
};
3.字符串相加
给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。
注意:
num1 和num2 的长度都小于 5100.
num1 和num2 都只包含数字 0-9.
num1 和num2 都不包含任何前导零。
你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式。
此处我将两个大数字符串转换成了数组,比如:
123 + 789 转换成了 [3, 2, 1] 和 [9, 8, 7] 的和
得数也用一个数组保存,注意进位和空数组的关系
/**
* 给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。
注意:
num1 和num2 的长度都小于 5100.
num1 和num2 都只包含数字 0-9.
num1 和num2 都不包含任何前导零。
你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式。
*/
/**
* 思路:与字符串相乘的思路类似,注意两个数组的长度不一样长而且注意前导0
*/
/**
* @param {string} num1
* @param {string} num2
* @return {string}
*/
var addStrings = function (num1, num2) {
const sum = [];
const len = num1.length > num2.length ? num1.length : num2.length;
num1 = num1.split('').reverse();
num2 = num2.split('').reverse();
for (let i = 0; i < len; i++) {
let number1 = num1[i] ? Number(num1[i]) : 0;
let number2 = num2[i] ? Number(num2[i]) : 0;
if (sum[i] === undefined) {
sum[i] = number1 + number2;
} else {
sum[i] += number1 + number2;
}
if (sum[i] > 9) {
if (sum[i + 1] === undefined) {
sum[i + 1] = ~~(sum[i] / 10);
} else {
sum[i + 1] += ~~(sum[i] / 10);
}
}
sum[i] = sum[i] % 10;
}
return sum.reverse().join('');
};
以上,是字符串的初始算法中个人觉得不错的题目,对于字符串,还需要熟悉正则表达式的使用。