找出最长的神奇数列
1.题目:
小F是一个好学的中学生,今天他学习了数列的概念。他在纸上写下了一个由
0
和1
组成的正整数序列,长度为n
。这个序列中的1
和0
交替出现,且至少由 3 个连续的0
和1
组成的部分数列称为「神奇数列」。例如,10101
是一个神奇数列,而1011
不是。现在,小F想知道在这个序列中,最长的「神奇数列」是哪一个。你能帮他找到吗?如果有多个神奇数列,那么输出最先出现的一个。
测试样例
样例1:
输入:
inp = "0101011101"
输出:'010101'
样例2:
输入:
inp = "1110101010000"
输出:'10101010'
样例3:
输入:
inp = "1010101010101010"
输出:'1010101010101010'
2.分析:
1.神奇数列的定义,是从左到右读取,如果左边的数字和右边数字不同,继续读取。
2.一组数可能有多组神奇数列,如’101001010’ 包含 ‘1010‘ 和 ‘01010‘,应返回最长的
3.可以先读取满足条件的数据,存放在数组里,比较多组数组,找出最长的
3.解决:
3.1 二维数组
我们可以用一个二维数组存放满足规则的数组
判断左右的数是否不一致,因为题目里只有0和1,可以转为数字之后,通过异或(XOR)操作去判断。左右不一致的数字,异或操作返回结果为1。实现了isReverseNum
函数。
1^0 // 1
0^0 // 0
1^0 // 0
0^1 // 1
// 找出二维数组里,长度最长的一项
function getLongestList<T>(list: Array<T[]>): T[] {
let result: T[] = [];
list.forEach((item) => {
if (item.length > result.length) {
result = item;
}
});
return result;
}
// 判断是否为相反的数(1和0相反,通过异或操作判断)
const isReverseNum = (prev: number, next: number) => {
return (prev ^ next) === 1;
};
// 获取相反的数 1->0 0->1
const getReverseNum = (char: string | number): number =>
Number(char) === 1 ? 0 : 1;
const searchNumList = (char: string) => {
let index = 0;
const result: Array<number[]> = []; // 存储二维数组
let storeIndex = 0; // 当前存储的下标
let prevNum: number = getReverseNum(char[0]);
while (index < char.length) {
const currentNum = Number(char[index]);
// 满足条件,加入到二维数组
if (isReverseNum(prevNum, currentNum)) {
result[storeIndex] = [...(result[storeIndex] || []), currentNum];
prevNum = currentNum;
index++;
}
// 不满足条件,下标自增
else {
prevNum = getReverseNum(currentNum);
index++;
storeIndex++;
}
}
return result;
};
function solution(inp: string): string {
const list = searchNumList(inp);
const result = getLongestList(list);
if (result.length < 3) return "";
return result.join("");
}
function main() {
// Add your test cases here
console.log(solution("0101011101") === "010101");
console.log(solution("1110101010000") === "10101010");
console.log(solution("1010101010101010") === "1010101010101010");
}
main();
这样的解法可以满足条件,但是二维数组比较占据空间,还可以用其他的解法。
3.2 一维数组
二维数组每次有数据,都直接存入,最后再比较。其实可以优化,在存入前去判断,用替换代替直接存入,优化:
由于条件判断不满足,以及while语句结束,可能currentList都有更新,所以调用updateResult去判断是否存入。
// 判断是否为相反的数(1和0相反,通过异或操作判断)
const isReverseNum = (prev: number, next: number) => {
return prev + next === 1;
};
// 获取相反的数 1->0 0->1
const getReverseNum = (char: string | number): number => 1 - Number(char);
// 更新结果数组
const updateResult = (currentList: number[], result: number[]): void => {
if (currentList.length > result.length && currentList.length > 3) {
result.splice(0); // 清空原数组
for (let i = 0; i < currentList.length; i++) {
result[i] = currentList[i]; // 复制新数组
}
}
};
const searchNumList = (char: string) => {
let result: number[] = []; // 存储符合条件的数组
const currentList: number[] = []; // 符合本次检索的数组
let index = 0;
while (index < char.length) {
const currentNum = Number(char[index]); // 本次检索的数字
const prevNum =
index === 0 ? getReverseNum(currentNum) : Number(char[index - 1]); // 本次需要取反的数字
// 满足条件,放入数组
if (isReverseNum(prevNum, currentNum)) {
currentList.push(currentNum);
index++;
}
// 不满足条件,判断是否要存入result,如果比result的数量多,超过三个,存入,清空当前检索的数组
else {
updateResult(currentList, result);
currentList.length = 0;
index++;
}
}
updateResult(currentList, result);
return result;
};
function solution(inp: string): string {
const list = searchNumList(inp);
return list.join("");
}
function main() {
// Add your test cases here
// console.log(solution("0101011101") === "010101");
// console.log(solution("1110101010000") === "10101010");
console.log(solution("1010101010101010") === "1010101010101010");
}
main();
3.3 滑动窗口
这道题目实际上是要提取满足条件的最长子字符串。可以用滑动窗口的思路去解决。
思路:
维护左右两个指针。
当右指针没有到达字符串尾部,能继续循环。
如果满足匹配条件,右指针不断增加
如果不满足,左指针移动到右指针位置,继续查找
function findMagicSequence(inp: string): string {
let left = 0;
let right = 0;
let maxLength = 0;
let maxSeq = "";
while (right < inp.length) {
// 扩大右边界直到不满足交替条件或者达到字符串末尾
while (right < inp.length - 1 && inp[right] !== inp[right + 1]) {
right++;
}
// 计算当前窗口的长度
const windowLength = right - left + 1;
// 如果窗口长度大于等于3,更新最长的神奇数列
if (windowLength >= 3 && windowLength > maxLength) {
maxLength = windowLength;
maxSeq = inp.substring(left, right + 1);
}
// 移动左边界到下一个位置
left = right + 1;
right = left;
}
return maxSeq;
}
function main() {
console.log(findMagicSequence("0101011101")); // '010101'
console.log(findMagicSequence("1110101010000")); // '10101010'
console.log(findMagicSequence("1010101010101010")); // '1010101010101010'
}
main();