放肆青春的博客
首页
前端
算法
网络
面试
技术
后端
运维
杂项
数据库
工具
网址
电脑
个人
文章
  • 分类
  • 标签
  • 归档
github (opens new window)
gitee (opens new window)

放肆青春

一个前端菜鸟的技术成长之路
首页
前端
算法
网络
面试
技术
后端
运维
杂项
数据库
工具
网址
电脑
个人
文章
  • 分类
  • 标签
  • 归档
github (opens new window)
gitee (opens new window)
  • 算法基础

    • 数据结构和算法
    • 算法blog
    • 算法基础
    • 算法思维
  • 算法汇总

    • 常见算法题
    • 穷举算法(枚举算法)
    • 递归
    • 二分法
    • 双指针

      • 双指针
      • 双指针算法题
      • 滑动窗口
      • 滑动窗口算法题
    • 回溯法

      • 回溯法
      • 回溯法算法题
    • 分治算法
    • 贪心算法

      • 贪心算法
      • 贪心算法题
    • 动态规划

      • 动态规划
      • 动态规划算法题
  • 排序算法

    • 排序算法
    • 1. 冒泡排序
    • 2. 选择排序
    • 3. 插入排序
    • 4. 希尔排序
    • 5. 归并排序
    • 6. 快速排序
    • 7. 堆排序
    • 8. 计数排序
    • 9. 桶排序
    • 10. 基数排序
  • 数据结构

    • 数组

      • 数组概览
      • 数组算法题
    • 字符串

      • 字符串概览
      • 字符串算法题
        • 字符串算法题
          • 1.验证回文串【L125】
          • 2.最长回文子串【L5】
          • 3.无重复字符的最长子串【L3 O48】
          • 4.最小覆盖子串【L76】
          • 5.回文子串【L647】
          • 6.反转字符串【L344】
          • 7.反转字符串中的单词 III(L557)
          • 8.字符串解码【L394】
          • 10. 每一个字符及其出现的次数
    • 树

      • 树概览
      • 树算法题
    • 链表

      • 链表概览
      • 双向链表
      • 链表算法题
    • 队列

      • 队列概览
      • 队列算法题
    • 堆

      • 堆概览
      • 堆算法题
    • 散列表(哈希表)

      • 散列表(哈希表)概览
      • 散列表(哈希表)算法题
    • 栈

      • 栈概览
      • 栈算法题
    • 图

      • 图概览
      • 图算法题
  • algorithm
放肆青春
2021-09-07

字符串算法题

# 字符串算法题

# 1.验证回文串【L125】

  1. 双指针

思路:用正则去掉无关字符,然后对撞指针判断左右两边是否是相同的字符

复杂度:时间复杂度 O(n),空间复杂度 O(1)

var isPalindrome = function(s) {
  var a = s.toLocaleLowerCase().match(/[a-z0-9]+/g);
  if (!a) return true;
  var slong = a.join("");
  var left = 0;
  right = slong.length - 1;
  while (left < right) {
    if (slong[left] == slong[right]) {
      left++;
      right--;
    } else {
      return false;
    }
  }
  return true;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 2.最长回文子串【L5】

  1. 双指针

解题思路:如果是回文子串,那么它的左右两边的元素肯定是对称的,我们可以使用左右指针,从当前元素向两边扩散,以找到最长字串。

时间复杂度:O(n^2)

空间复杂度 O(1)

var longestPalindrome = function(s) {
  let res = "";
  for (let i = 0; i < s.length; i++) {
    // 寻找长度为奇数的回文子串(以当前元素向两边扩散)
    const s1 = palindrome(s, i, i);
    // 寻找长度为偶数的回文子串(以s[i],s[i + 1])向两边扩散
    const s2 = palindrome(s, i, i + 1);
    res = res.length > s1.length ? res : s1;
    res = res.length > s2.length ? res : s2;
  }
  return res;
};
function palindrome(s, l, r) {
  // 左右指针,从s[l]和s[r]向两边扩散,找到最长回文串
  while (l >= 0 && r < s.length && s[l] == s[r]) {
    l--;
    r++;
  }
  return s.substr(l + 1, r - l - 1);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  1. 动态规划

时间复杂度: O(n^2)

空间复杂度: O(n)

function longestPalindrome(s: string): string {
  const n = s.length;
  let [left, right] = [0, 1];
  let pre: number[] = [];
  let cur: number[] = [0, 1];
  for (let i = 0; i < n; i++) {
    for (const j of pre) {
      if (s[i] === s[j - 1]) {
        cur.push(j - 1);
        if (i - j + 2 > right - left) [left, right] = [j - 1, i + 1];
      }
    }
    [cur, pre] = [[i + 1, i + 2], cur];
  }

  return s.slice(left, right);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

参考:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/5zui-chang-hui-wen-zi-chuan-cong-di-gui-44xrh/ (opens new window)

# 3.无重复字符的最长子串【L3 O48】

  1. 滑动窗口 + set

时间复杂度:O(N)

空间复杂度:O(n),即 set 的空间,最差的情况是 O(n)

var lengthOfLongestSubstring = function(s) {
  const set = new Set(); //判断滑动窗口内是否有重复元素
  let i = 0, //滑动窗口右边界
    j = 0, //滑动窗口左边界
    maxLength = 0;
  if (s.length === 0) {
    //极端情况
    return 0;
  }
  for (i; i < s.length; i++) {
    if (!set.has(s[i])) {
      //当前元素不在set中 就加入set 然后更新最大长度,i++继续下一轮循环
      set.add(s[i]);
      maxLength = Math.max(maxLength, set.size);
    } else {
      //set中有重复元素不断让j++ 并删除窗口之外的元素 直到滑动窗口内没有重复的元素
      while (set.has(s[i])) {
        set.delete(s[j]);
        j++;
      }
      set.add(s[i]); //放心将s[i]加入set中
    }
  }
  return maxLength;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  1. 滑动窗口
/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
  var str = [],
    maxLength = 0;
  for (let i = 0; i < s.length; i++) {
    let index = str.indexOf(s[i]);
    if (index != -1) {
      str.splice(0, index + 1);
    }
    str.push(s[i]);
    maxLength = Math.max(maxLength, str.length);
  }
  return maxLength;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 4.最小覆盖子串【L76】

  1. 滑动窗口

解题思路:

(1)我们在字符串 S 中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引闭区间 [left, right] 称为一个「窗口」。

(2)我们先不断地增加 right 指针扩大窗口 [left, right],直到窗口中的字符串符合要求(包含了 t 中的所有字符)

(3)我们停止增加 right,转而不断增加 left 指针缩小窗口 [left, right],直到窗口中的字符串不再符合要求(不包含 T 中的所有字符了)。同时,每次增加 left,我们都要更新一轮结果

(4)重复第 2 和第 3 步,直到 right 到达字符串 S 的尽头

思路的本质:增加窗口右边界,寻找一个可行解,在找到可行解的情况下增加窗口左边界,优化可行解,找到最优解

var minWindow = function(s, t) {
  // 需要的
  let need = {};
  // 窗口中的字符
  let window = {};
  for (let a of t) {
    // 统计需要的字符
    need[a] = (need[a] || 0) + 1;
  }
  // 左右指针
  let left = 0,
    right = 0;
  let valid = 0;
  // 最小覆盖子串的起始索引及长度
  let start = 0,
    len = Number.MAX_VALUE;
  while (right < s.length) {
    // 即将移入窗口的字符
    let c = s[right];
    // 右移窗口
    right++;
    if (need[c]) {
      // 当前字符在需要的字符中,则更新当前窗口统计
      window[c] = (window[c] || 0) + 1;
      if (window[c] == need[c]) {
        // 当前窗口和需要的字符匹配时,验证数量增加1
        valid++;
      }
    }
    // 当验证数量与需要的字符个数一致时,就应该收缩窗口了
    while (valid == Object.keys(need).length) {
      // 更新最小覆盖子串
      if (right - left < len) {
        start = left;
        len = right - left;
      }
      //即将移出窗口的字符
      let d = s[left];
      // 左移窗口
      left++;
      if (need[d]) {
        if (window[d] == need[d]) {
          valid--;
        }
        window[d]--;
      }
    }
  }
  return len == Number.MAX_VALUE ? "" : s.substr(start, len);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

# 5.回文子串【L647】

# 6.反转字符串【L344】

# 7.反转字符串中的单词 III(L557)

  1. 双指针
/**
 * @param {string} s
 * @return {string}
 */
var reverseWords = function(s) {
  let arr = s.split("");

  let l = 0,
    r = l;
  while (l < arr.length) {
    //找到结尾的空格
    while (arr[r] && arr[r] !== " ") {
      r++;
    }

    //反转单词
    for (let i = l, j = r - 1; i < j; i++, j--) {
      [arr[i], arr[j]] = [arr[j], arr[i]];
    }

    //跳到下一个单词
    l = r + 1;
    r = l;
  }

  return arr.join("");
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  1. 数组 api
var reverseWords = function(s) {
  let arr = s
    .split("")
    .reverse()
    .join("");
  return arr
    .split(" ")
    .reverse()
    .join(" ");
};
1
2
3
4
5
6
7
8
9
10
/**
 * @param {string} s
 * @return {string}
 */
var reverseWords = function(s) {
  function reverse(str) {
    //功能函数,反转字符串。
    let newStr = "";
    for (let i of str) {
      newStr = i + newStr;
    }
    return newStr;
  }
  let sArr = s.split(" ");
  sArr = sArr.map((i) => reverse(i)); //反转每个字符串保存在sArr中;
  return sArr.join(" ");
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 8.字符串解码【L394】

# 10. 每一个字符及其出现的次数

function getMaxLengthStr(str) {
  let obj = {}; //定义一个新对象
  //循环遍历字符串
  for (let i = 0; i < str.length; i++) {
    // charAt()方法,返回某个指定位置的字符
    let char = str.charAt(i);
    // char就是对象obj的一个属性,obj[char]是属性值,obj[char]控制出现的次数(char是键值对中的键,obj[char]是值)
    if (obj[char]) {
      obj[char]++; //次数加1
    } else {
      obj[char] = 1; //若第一次出现,次数记为1
    }
  }
  // 输出的是完整的对象,记录着每一个字符及其出现的次数
  console.log(obj);

  // 遍历对象,找到出现次数最多的字符的次数
  let max = 0;
  // let maxChar = "";
  for (let key in obj) {
    if (max < obj[key]) {
      max = obj[key]; // max始终储存次数最多的那个
      // maxChar = key; //那么对应的字符就是当前的key
    }
  }
  // console.log("最多的字符是" + maxChar);
  // console.log("出现的次数是" + max);

  // 遍历对象,找到出现次数最多的字符和其次数
  for (let key in obj) {
    if (obj[key] == max) {
      //对应最多的字符就是当前的key
      //console.log(key);
      console.log("最多的字符是" + key);
      console.log("出现的次数是" + max);
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
更新时间: 1/12/2022, 8:42:58 PM
字符串概览
树概览

← 字符串概览 树概览→

最近更新
01
前端权限管理
02-24
02
vue2指令
02-24
03
vue2 hook
02-24
更多文章>
Theme by Vdoing | Copyright © 2019-2022 放肆青春
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式