算法-字符串

33 阅读5分钟
1. 无重复字符的最长子串
var lengthOfLongestSubstring = function(s) {
  let l = 0; // 定义左指针
  let r=0
  let res = 0; // 结果
  let map = new Map(); // 存放字符和对应下标
  let len = s.length
  while (r<len) {
    // 两个重复的情况 所以要 map.get(s[r]) >= l
    if (map.has(s[r]) && map.get(s[r]) >= l) {
      l = map.get(s[r]) + 1; // 出现重复 取其下一个  出现重复的和最后边的重复了  就取其下一个正好
    }
    res = Math.max(res, r - l + 1); // 计算结果   ab 字符串是1-0+1
    map.set(s[r], r); // 存下每个字符的下标
    r++
  }
  return res;
};
15. 最长回文子串
var longestPalindrome = function(s) {
    let start =0;
    let end =0;
    let maxLen = 0
    
   // 从中间扩散到两边 一直相等一直变长
    function getOther(left, right){
        while (left>=0&&right<s.length&&s[left]===s[right]){
            left--;
            right++;
        }
        // 进来基数时候进来就会进循环  偶数时候不相等也默认是1
        return right - left - 1
    }
    for(let i=0;i<s.length;i++){
        // 考虑奇数偶数
        const len1 = getOther(i, i);// 奇数
        const len2 = getOther(i, i+1)// 偶数
        const len = Math.max(len1,len2)
        if(maxLen<len){
            maxLen = len
            start = i - Math.floor((len-1)/2)// 奇数的时候 向前len-1的一半********
            end = i + Math.floor(len/2)
        }
    }
    return s.substring(start,end+1)
};
4. 比较版本号

版本号特点是字符串的。用.分开的字符串。从高位到底位只要大就大 和 字符串的总长度无关

var compareVersion = function(version1, version2) {
  	// map(NUmber) 直接转换成number的数组 可以直接比较;大于小于的时候直接返回;循环完没有返回则返回0
    var v1 = version1.split('.').map(Number)
    var v2 = version2.split('.').map(Number)
    var vm = Math.max(v1.length, v2.length)
    for(let i=0;i<vm;i++){
        if((v1[i]||0)>(v2[i]||0)){
            return 1;
        }
        if((v1[i]||0)<(v2[i]||0)){
            return -1;
        }
    }
    return 0;
};
7. 有效的括号

栈存储左括号,遇到右括号 与之对应则弹出 没有对应返回false;最后栈空则全部匹配

var isValid = function(s) {
    const mapping = {
        ')': '(',
        '}': '{',
        ']': '['
    };
    let stack = []
    for(char of s){
      	// 如果是左侧存入栈  如果是右侧看是不是和栈顶的一样 
        if(mapping[char]){
          // 如果不一样 返回false   一样的话pop出栈
            if(mapping[char] !== stack.pop()){
                return false
            }
        }else {
            stack.push(char)
        }
    }
   // 最后栈空 为正好全部匹配
    return  stack.length === 0

};
8. 字符串相加

进制两个相加时候 从底位开始 取余和删除。注意字符串转成数字相加

var addStrings = function(num1, num2) {
    let superfluous = 0;// 默认没有进位
    let result = ''// 默认是空字符串
    let i=num1.length -1,j=num2.length-1
    // i>=0 j>=0 一直循环到最后
    while(i>=0||j>=0||superfluous>0){
        // ~~(num1[i]||0) 取出来的是字符串 一定要转成number
        const sum = ~~(num1[i]||0) + ~~(num2[j]||0) + superfluous
        // sum/10 进位的值
        superfluous = Math.floor(sum/10)
        // sum%10 个位  当前位的值
      	result = (sum%10) + result
        i--;
        j--;
    }
    return result;

};
27. 最大交换 交换完数最大

给定一个非负整数,你至多可以交换一次数字中的任意两位。返回你能得到的最大值。

只要后边的数「最大数」比前面的数大 移动到前面来就是最大数

var maximumSwap = function(num) {
    const numArr = num.toString().split('')
    const lastArr = Array(10).fill(-1);

    // 存储每个数字的位置
    for(let i = 0;i<numArr.length;i++){
        lastArr[numArr[i]] = i
    }
    for(let i=0;i<numArr.length;i++){
        // 比当前值大 且位置在当前值后边      遍历9- numarr【ℹ️】 就是找 比他大的数
        for(let j=9;j>numArr[i];j--){
            if(lastArr[j]>i){
                // 交换是交换位置 lastArr[j] 才是j的位置 并不是j
                [numArr[i], numArr[lastArr[j]]] = [numArr[lastArr[j]], numArr[i]]
                return Number(numArr.join(''))
            }
        }
    }
    return num;
};
51. Excel表列名称
var convertToTitle = function(columnNumber) {
    let result = ''
    while (columnNumber>0){
        // 列在0 开始 都要-1
        const current =(columnNumber-1)%26;
        result = String.fromCharCode(current + 65) + result
        columnNumber = Math.floor((columnNumber-1)/26)
    }
    return result
};
52. Excel 表列序号 相当于26进制
var titleToNumber = function(columnTitle) {
    // let result = 0
    // let step = 1
    // while (columnTitle){
    //     const end = columnTitle.substring(columnTitle.length-1,columnTitle.length)
    //     result += step*(end.charCodeAt(0)-64)
    //     step *=26;
    //     columnTitle = columnTitle.substring(0,columnTitle.length-1)
    //     console.log(columnTitle)
    // }
    // return result;
  
  	// uniCode 码; a:97 A:65 ;str.charCodeAt(i)如果不写i 默认取str的unicode
  	// 最大开始遍历 每次*26。 进制 如果是10进制 就*10

    let result = 0;
    for (let i = 0; i < columnTitle.length; i++) {
        result = result * 26 + (columnTitle.charCodeAt(i) - 64);
    }
    return result;
};
82.回文数

从低位开始。倒过来

var isPalindrome = function(x) {
    if(x<0){
        return false
    }
    let tempX = x
    let rt = 0
    while (x) {
        rt = 10*rt + x%10 // 加上一位。每次加一位 原来的相左移动一位所有*10
        x = Math.floor(x/10)// 向右移动 /10
    }
    if(rt == tempX){
        return true
    } else {
        return false
    }
};
70.替换空格
// 注意一点 字符串不是引用类型 直接改的话不会变化;s[2] = '20%' s是不发生变化的;
// 所有用一个字符串一直拼接
function replaceSpace(s){
    let rt = ''
    for(let i=0,len=s.length;i<len;i++){
        if(s[i] === ' '){
        rt += '%20'
        } else {
        rt += s[i]
        }
    }
    return rt;
}
98.写一个算法 实现一个字符串的规则解析:

例子:a(b)<2>c 输出:abbc,a(b(c)<3>de)<2>f 输出abcccdebcccdef;()代表重复内容,<>代表重复的次数

function parseAndRepeat(str) {
  let stack = ['']; // 初始化栈,栈底是空字符串,用于累加结果
  let i = 0; // 遍历字符串的索引

  while (i < str.length) {
    let char = str[i];

    if (char === '(') {
      // 遇到 '(',开始新的重复区块
      stack.push('');
      i++;
    } else if (char === ')') {
      // 遇到 ')',结束当前重复区块
      let repeatedStr = stack.pop(); // 获取当前重复区块内容
      i++;

      // 查找重复次数
      let repeatTimes = 0;
      if (str[i] === '<') {
        i++;
        let numStart = i;
        while (str[i] !== '>') {
          i++;
        }
        repeatTimes = parseInt(str.slice(numStart, i));
        i++;
      }

      stack[stack.length - 1] += repeatedStr.repeat(repeatTimes);
    } else {
      // 非特殊字符,直接加入当前字符串
      stack[stack.length - 1] += char;
      i++;
    }
  }

  return stack.join(''); // 将栈中的所有字符串合并
}

// 示例用法
console.log(parseAndRepeat('a(b)<2>c')); // 输出:abbc
console.log(parseAndRepeat('a(b(c)<3>de)<2>f')); // 输出:abcccdebcccdef