leetCode算法第三天

继续练习leetcode中关于字符串的算法题,越练越觉得自己编码思想还很欠缺,继续努力。


在这里插入图片描述

有效的括号

leetcode链接:https://leetcode.cn/problems/valid-parentheses/

解题思路:无论这三种符号谁在里谁在外,或者单独存在,只要是有效的括号,我们都可以通过将字符串中()或者[]或者{}替换成"",下一次循环替换时,外层的括号也会被替换,直到最外层。

理论上最多需要替换字符串长度的二分之一,因为括号总是成对出现,如果一直到最后都没能将字符串彻底清空,表明有不成对的括号出现,即不是有效的括号。

/** https://leetcode.cn/problems/valid-parentheses/
 * @param {string} s
 * @return {boolean}
 */
var isValid = function (s) {
    
    
  // 先判断是否是偶数个
  if (typeof s !== "string" || s.length % 2) {
    
    
    return false;
  }

  const length = s.length;

  for (let i = 0; i <= length / 2; i++) {
    
    
    s = s.replace("()", "").replace("[]", "").replace("{}", "");

    if (s.length === 0) {
    
    
      break;
    }
  }

  return s.length === 0;
};

括号生成

leetcode 链接:https://leetcode.cn/problems/generate-parentheses/

解题思路:要生成n对()的字符串,就意味着要递归n次,每一次又要在之前的字符串的每一个位置尝试着添加,循环上一次结果的长度次数。

比如当n为3时,需要递归三次,第一次就是一个"()“,第二次就在第一次的基础上,分别从0的位置一直到最后的位置尝试加”()“,所以第二次可能是”()()“,”(())“,”()()",然后发现1和3相同,所以只保存一个,将第二次循环的每一个不重复的结果进行第三次递归。

所以,我们n的数,其实就是递归的次数,每一次递归里面都需要循环,循环的次数就是上一次递归结果的长度。

/** https://leetcode.cn/problems/generate-parentheses/
 * @param {number} n
 * @return {string[]}
 */
var generateParenthesis = function (n) {
    
    
  const result = [];

  if (typeof n !== "number" || n <= 0) {
    
    
    return result;
  }

  let otherStr = [];

  const generateString = function (n, s) {
    
    
    for (let i = 0; i <= s.length; i++) {
    
    
      // 在s的每一个位置分别插入()
      let newStr = s.slice(0, i) + "()" + s.slice(i);

      if (n === newStr.length / 2) {
    
    
        // 最后要检查一下result中是否已经有了该字符串,可能出现重复的情况,比如将()放在 0和最后的位置,对于 "()"来说是一样的
        if (!result.includes(newStr)) {
    
    
          result.push(newStr);
        }
      } else {
    
    
        if (!otherStr.includes(newStr)) {
    
    
          // 如果otherStr中已经出现过,表明之前已经执行了,不需要再放入
          otherStr.push(newStr);
          generateString(n, newStr);
        }
        // generateString(n, newStr)
      }
    }
  };

  generateString(n, "");

  return result;
};

串联所有单词的子串

leetcode 链接:https://leetcode.cn/problems/substring-with-concatenation-of-all-words/

解题思路:先将s按照要求的长度(words里面所有元素加起来的长度)进行切割片段,切割出来的每一个片段进行循环判断,是否是由words里面的元素随机顺序组合出来的。

如何判断?将每一个片段按照words里单个元素的长度再次进行切割,将这些小小的片段去words里面一一匹配,只要全部都能匹配上,就符合要求,否则不符合。并把这些片段在s中的坐标返回即可。

/**
 * @param {string} s https://leetcode.cn/problems/substring-with-concatenation-of-all-words/
 * @param {string[]} words
 * @return {number[]}
 */
var findSubstring = function (s, words) {
    
    
  // 先判断一下words的元素的长度和words的长度
  let length = 0;
  let result = [];
  if (words.length) {
    
    
    length = words.length * words[0].length;
  }

  const array = [];
  // 将s字符串按照length的长度进行切割,并将所有切割后的内容存放到数组中,必须得保存当前的下标,这个下标需要精准返回。
  for (let i = 0; i <= s.length - length; i++) {
    
    
    array.push({
    
     string: s.slice(i, i + length), index: i });
  }

  // 我们需要遍历这个数组,并将里面每一个元素字符串按照words[0].length 的长度切割成一个个小的字符串
  array.forEach((item) => {
    
    
    let itemSplitArray = [];
    let i = 0;
    while (i < item.string.length) {
    
    
      itemSplitArray.push(item.string.slice(i, i + words[0].length));
      i = i + words[0].length;
    }

    // 切割出来的这个itemSplitArray的元素需要去words中进行匹配,以确保每一个元素都在words中能够找到,并且不是重复的。
    let newWords = JSON.parse(JSON.stringify(words));
    let isSuccess = true;

    for (const split of itemSplitArray) {
    
    
      let index = newWords.findIndex((findItem) => {
    
    
        return split === findItem;
      });

      if (index >= 0) {
    
    
        newWords[index] = undefined;
      } else {
    
    
        // 只要有一个没找到即index为-1,就认为这个item.string不符合条件,就找下一个。
        isSuccess = false;
        break;
      }
    }

    if (isSuccess) {
    
    
      result.push(item.index);
    }
  });

  return result;
};

最长有效括号

leetcode 链接:https://leetcode.cn/problems/longest-valid-parentheses/

这道题我用了两种解法,第一种解法能行得通,容易理解,但是效率很低
甚至不能通过leetcode的效率检测。逻辑和目的实际上没问题。

/** 最长有效括号 https://leetcode.cn/problems/longest-valid-parentheses/
 * @param {string} s
 * @return {number}
 */
var longestValidParentheses = function (s) {
    
    
  // 最长有效,我们就从最长开始

  let targetArray = [];

  for (let i = s.length; i >= 2; i--) {
    
    
    if (i % 2 !== 0) {
    
    
      continue;
    }
    for (let j = 0; j <= s.length - i; j++) {
    
    
      let targetStr = s.slice(j, j + i);
      targetArray.push(targetStr);
    }
  }

  // 我们不在双重for循环里判断targetStr是不是符合要求的有效括号,提出来可能判断可能会好一些,数组最前面的item越长,
  // 所以按照数组的顺序,只要判断出当前的item符合要求就直接返回结果,因为剩下的即使符合要求,也比当前的item短
  for (const item of targetArray) {
    
    
    let newItem = item;

    // 判断是否是有效括号其实很简单,通过之前的题目,我们知道,将字符串里面的()全部替换成“”,重复数次即可
    for (let n = 0; n <= item.length / 2; n++) {
    
    
      newItem = newItem.replace("()", "");

      if (newItem.length === 0) {
    
    
        return item.length;
      } else if (newItem.length % 2 !== 0) {
    
    
        break;
      }
    }

    if (newItem.length === 0) {
    
    
      return item.length;
    }
  }

  // 如果整个targetArray遍历完了都找不到符合要求的,直接返回0
  return 0;
};

第二种解法利用栈stack的思想,遇到"("即入栈,遇到")"即出栈,但对于最长有效长度的认定,的确需要认真思考。

在这里插入图片描述
如果遇到)出栈后还为空,就将当前的下标作为参考值(和最开始的-1一样,都是参考值),存入栈中。
在这里插入图片描述

/** 最长有效括号 https://leetcode.cn/problems/longest-valid-parentheses/
 * @param {string} s
 * @return {number}
 */

var longestValidParentheses = (s) => {
    
    
  let maxLen = 0;
  const stack = [];
  stack.push(-1);
  for (let i = 0; i < s.length; i++) {
    
    
    const c = s[i];
    if (c == '(') {
    
           // 左括号的索引,入栈
      stack.push(i);
    } else {
    
                  // 遍历到右括号
      stack.pop();        // 栈顶的左括号被匹配,出栈
      if (stack.length) {
    
     // 栈未空
        const curMaxLen = i - stack[stack.length - 1]; // 计算有效连续长度
        maxLen = Math.max(maxLen, curMaxLen);          // 挑战最大值
      } else {
    
                // 栈空了
        stack.push(i);    // 入栈充当参照
      }
    }
  }
  return maxLen;
};

猜你喜欢

转载自blog.csdn.net/glorydx/article/details/130225160