第一节:字符串相关(最长公共前缀、无重复最长子串、最长回文子串)

一. 最长公共前缀

1. 题目描述

 编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""

 详见:https://leetcode.cn/problems/longest-common-prefix/

 难度:【简单】

2. 思路分析

  (1). 默认以数组中的第1个元素为前缀 prefix

  (2). 遍历数组的每一个元素

      A. 利用indexof判断是否以该prefix为开头

      B. 如果不是, 则将prefix从尾部减去1, 继续利用indexof判断

      C. 如果是, 则跳出循环,进行数组中下一个元素的判断

  (3). 当prefix的长度为0时, 表示没有公共前缀

3. 代码实操

function longestCommonPrefix(strs: string[]): string {
	//边界判断
	if (strs.length <= 0) return '';

	//业务逻辑
	let prefix = strs[0];
	for (let i = 1; i < strs.length; i++) {
		while (strs[i].indexOf(prefix) != 0) {
			prefix = prefix.slice(0, prefix.length - 1);
			if (prefix === '') return '';
		}
	}

	return prefix;
}

 

二. 无重复最长子串

1. 题目描述

  给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度

  详见:https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/

  难度:【中等】

2. 思路分析

这里采用双指针left、right的解题思路

  (1). right指针负责从头扫描到尾部

  (2). left指针默认指向0的位置,

  (3). 在发现right指针出现重复字符的时候 并且 出现的位置要>=left位置, 将left改为之前出现字符位置+1

  (4). 每次遍历可以求出

         currentLength=right-left+1;

         maxLength=Math.Max(maxLength,currentLength)

 补充:

      A. 字符串str可以直接通过 str[i] 的模式获取第i个位置的字符

      B. 用map<string,number>记录  s[i]的值 和  对应的索引

 

3. 代码实操

function lengthOfLongestSubstring(s: string): number {
	let n = s.length;
	let map = new Map<string, number>(); //map结构存放 s[i]的值 和  对应的索引
	let maxLength = 0; //最大长度

	//双指针left,right
	let left = 0;
	for (let right = 0; right < n; right++) {
		const sValue = s[right];

		//1. 判断之前是否出现过该字符
		if (map.has(sValue) && map.get(sValue)! >= left) {
			left = map.get(sValue)! + 1; //表示出现过
		}

		//2. 存放到map里 (必须放在上面的判断之后)
		map.set(sValue, right);

		//3. 获取当前长度
		let currentLength = right - left + 1;

		//4. 获取最大长度
		maxLength = Math.max(maxLength, currentLength);
	}

	return maxLength;
}

 

三. 最长回文子串

1. 题目描述

    给你一个字符串 s,找到 s 中最长的回文子串, 并输出。    如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。

    详见: https://leetcode.cn/problems/longest-palindromic-substring/description/

    难度:【中等】

 

2. 思路分析-中心扩展法

(1). 先封装一个中心扩展算法centerExpand,根据left和right指针位置,求回文串长度

(2). 定义最大回文串的开始、结束索引,start、end

(3). 开始遍历

   A. 有两种回文情况, 需要分别计算回文长度

   B. 求出上述两种情况的最大长度, 和 end-start+1 比较。 (也有写end-start的, end-start+1 表示的是回文长度)

        如果大于等于话,需要重新对start 和 end 赋值, 借助上述求得 maxlength

(4). 最终根据start 和 end 求回文字符串最长的。

 

3. 代码实操

PS:centerExpand中,最后为什么是right-left-1呢?    

      举例子:str="abbc", left=1,right=2, 进入while遍历,跳出遍历的时候 left=0,right=3了,此时是索引不是回文字符串的索引,

      而是额外执行了一次while内部操作, 回文串为bb,即长度为2, 即 right-left-1 。

function longestPalindrome(s: string): string {
	//边界判断
	let n = s.length;
	if (n <= 1) return s;

	//遍历求最大回文字符串
	let start = 0; //最大回文串的开始索引
	let end = 0; //最大回文串的结束索引
	for (let i = 0; i < n; i++) {
		//两种回文情况
		let length1 = centerExpand(s, i, i); // 如:cabad
		let length2 = centerExpand(s, i, i + 1); // 如:dbaabc
		let maxLength = Math.max(length1, length2);

		//求最大回文串开始、结束的索引
		//新的长度比原来保存的start/end要长, 重新赋值
		if (maxLength > end - start + 1) {
			const left = i - Math.floor((maxLength - 1) / 2); //要先-1
			const right = i + Math.floor(maxLength / 2);

			start = left;
			end = right;
		}
	}

	return s.substring(start, end + 1); // [), 所以要截取到end位置,需要传入end+1
}

/**
 * 求指定位置的回文字符串长度
 * @param s 待求的字符串
 * @param left 指针1
 * @param right 指针2
 * @returns
 */
function centerExpand(s: string, left: number, right: number): number {
	while (left >= 0 && right < s.length && s[left] === s[right]) {
		left--;
		right++;
	}
	return right - left - 1; //回文字符串长度 (公式详见上面的思路分析)
}

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @ 2024-02-28 10:06  Yaopengfei  阅读(14)  评论(0编辑  收藏  举报