这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战
无重复字符的最长子串
题目
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
题解
该题考察了字符串的一些用法(字符串截取、查找)。在遍历过程中,通过当前字符与前面无重复子字符串比较:
- 当前字符存在子串中,将子串左边界收缩到重复的下一位值;
- 不重复,则右边界继续扩大。 关于最大值,比较子串出现的最大长度。
例子:
s = "abcabcbb"
当开始时,子串的左右边界应该指向起始位置。当前截取的子串str应该为空。
子串str中不包含当前a字符,所以,扩大子串右边界,继续向下遍历。
当循环到第二个a时,情况如下:
此时截取的子串中包含了当前的字符,进行查找子串中出现重复的位置,将缩小左边界至重复位置的下一位。继续循环,取最大值。
当再次出现重复时:
依旧缩小左边界。在此,p1并不是简单的移动到子串重复位置的下一位。当前子串重复位置为0,下一位即1。但是如果移动到1的话,左边界就并未缩小。所以移动的时候,还需要加上左边界原始的位置。此时p1移动到2位置。
以此类推,在每次遍历中,取子串长度的最大数。最后遍历完成后,返回最大值即可。
代码
var lengthOfLongestSubstring = function (s) {
let p1 = 0, index = 0, max = 0
while (index <= s.length) {
let str = s.slice(p1, index)
let isExitIndex = str.indexOf(s[index])
if (isExitIndex > -1) p1 += isExitIndex + 1
max = Math.max(max, str.length)
index++
}
return max
};
字符串的排列
题目
给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 ****的排列。
换句话说,s1 的排列之一是 s2 的 子串 。
示例 1:
输入: s1 = "ab" s2 = "eidbaooo"
输出: true
解释: s2 包含 s1 的排列之一 ("ba").
题解
该题主要考察通过子串全排列能否联想到使用字符数组解决。说实话一开始我是没想到。。。
使用两个长度为26的数组,分别记录两个字符串每个字符出现的次数。用一个长度为26的数组记录s1中出现的次数。在遍历s2时,通过使用两个左右指针截取s2可能的子串。在用一个长度为26的数组记录截取的子串字符数。当s1的数组等于截取子串数组时就满足条件。
代码
var checkInclusion = function (s1, s2) {
let arr1 = new Array(26).fill(0)
let arr2 = new Array(26).fill(0)
for (let i = 0; i < s1.length; i++) {
arr1[s1[i].charCodeAt() - 'a'.charCodeAt()]++
}
let i = 0, j = 0
while (i < s2.length) {
arr2[s2[i].charCodeAt() - 'a'.charCodeAt()]++
while (j <= i && arr2[s2[j].charCodeAt() - 'a'.charCodeAt()] > arr1[s2[j].charCodeAt() - 'a'.charCodeAt()]) {
arr2[s2[j].charCodeAt() - 'a'.charCodeAt()]--
j++
}
i++
if (arr1.join('') === arr2.join('')) return true
}
return false
};
题目来源:leetcode