【第2期】前端算法精选-字符串系列

简介: 【第2期】前端算法精选-字符串系列

字符串的排列


LeetCode.567,难度中等


题目


给定两个字符串 s1s2,写一个函数来判断 s2 是否包含 s1 的排列。

换句话说,第一个字符串的排列之一是第二个字符串的子串。

示例1:

输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").
复制代码

示例2:

输入: s1= "ab" s2 = "eidboaoo"
输出: False
复制代码

注意:

  1. 输入的字符串只包含小写字母
  2. 两个字符串的长度都在 [1, 10,000] 之间


解法


理解一下题意,要求s1的字符串排列之一是第二个字符串的子串,比如ab是eidbaooo的子串,ba也是eidbaooo的子串,同样的baoo也是eidbaooo的子串,所以这个规则可以抽象一下,如果eidbaooo里面存在一个子串,该子串的字符和s1的字符相同,且该子串字符出现的次数和s1中的字符出现次数相同,因此,可以考虑滑动窗口的思路。

首先维护一个map1来保存s1的字符以及每个字符出现的次数,再维护一个map2来保存当前窗口中的每个字符以及每个字符出现的次数,如果map1和map2相同,则说明滑动窗口中的字符子串和s1的排列之一相同,否则继续往右滑动。

  1. 初始化,以s1长度为准,来构造两个map,map1 = { a: 1, b: 1 },map2 = { e: 1, i: 1 }。此时滑动窗口中的字符串是'ei'
  2. 从s2的第3个(前两个已经被初始化过)字符'd'开始遍历,map1和map2不同。此时窗口字符串是'ei',删掉左边的'e',更新map2= { i: 1 };加入第3个字符'd',更新map2 = { i: 1, d: 1 }
  3. 此时遍历到第4个字符'b',map1和map2不同。此时窗口字符串是'id',删掉左边的'i',更新map2={ d: 1 };加入第4个字符串'b',更新map2={ d: 1, b: 1 }
  4. 此时遍历到第5个字符'a',map1和map2不同。此时窗口的字符串是'db',删掉左边的'd',更新map2={ b: 1 };加入第5个字符串'a',更新map2={ b: 1, a: 1 }
  5. 此时遍历到滴6个字符'o',map1和map2相同,返回true

代码如下:

/**
 * @param {string} s1
 * @param {string} s2
 * @return {boolean}
 */
let checkMapEqual = function(m1, m2) { 
    let keys1 = Object.keys(m1), keys2 = Object.keys(m2);
    if(keys1.length !== keys2.length)
        return false;
    for(let i = 0;i < keys1.length;i++) {
        const curKey = keys1[i];
        if(m1[curKey] !== m2[curKey])
            return false;
    }
    return true;
}
let checkInclusion = function(s1, s2) {
    if(s1.length > s2.length)
      return false;
    let map1 = {}, map2 = {};
    const len1 = s1.length, len2 = s2.length;
    // 初始化map
    for(let i = 0;i < len1;i++) {
        if(map1[s1[i]]) {
            map1[s1[i]]++
        } else {
            map1[s1[i]] = 1;
        }
        if(map2[s2[i]]) {
            map2[s2[i]]++
        } else {
            map2[s2[i]] = 1;
        }
    }
    for(let i = len1;i < len2;i++) {
        if(checkMapEqual(map1, map2)) {
            return true;
        }
        // 将窗口最左边的字符删去
        const leftChar = s2[i-len1];
        if(map2[leftChar] === 1) {
            delete map2[leftChar];
        } else {
            map2[leftChar]--;
        }
        // 在窗口右边加入一个字符
        const rightChar = s2[i];
        if(map2[rightChar]) {
            map2[rightChar]++;
        } else {
            map2[rightChar] = 1;
        }
    }
    return checkMapEqual(map1, map2);
};
复制代码


字符串相乘


LeetCode.43,难度中等


题目


给定两个以字符串形式表示的非负整数 num1num2,返回 num1num2 的乘积,它们的乘积也表示为字符串形式。

示例 1:

输入: num1 = "2", num2 = "3"
输出: "6"复制代码

示例 2:

输入: num1 = "123", num2 = "456"
输出: "56088"复制代码

说明:

  1. num1num2 的长度小于110。
  2. num1num2 只包含数字 0-9
  3. num1num2 均不以零开头,除非是数字 0 本身。
  4. 不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。


解法


先分析一下题目字符串相乘,要想模拟两个数字相乘,需要解决逐位相乘、再逐个相加的问题,过程中需要注意正确进位,比如'123'和'456'相乘:

  1. 3和456相乘,得到1368;
  2. 2和456相乘,得到912,因为2是十位,所以得到9120;
  3. 1和456相乘,得到456,因为1是百位,所以得到45600;
  4. 把3次乘积相加,加的过程中也要注意逐位相加,别忘了进位

代码如下:

/**
 * @param {string} num1
 * @param {string} num2
 * @return {string}
 */
const multiplyStep = (num1, pos, num2) => {
  let res = '';
  let carry = 0;
  for(let i = num2.length-1;i >= 0;i--) {
    const cur = num2[i];
    let product = parseInt(cur)*num1;
    if(carry) {
      product += carry;
      carry = 0;
    }
    if(product >= 10) {
      carry = parseInt(product/10);
      product = product%10
    }
    res = product + res;
  }
  if(carry) {
    res = carry + res;
  }
  while(pos) {
    res += 0;
    pos--;
  }
  return res;
}
const addStep = (num1, num2) => {
  let len1 = num1.length;
  let len2 = num2.length;
  let num1Reversed = num1.split('').reverse().join('');
  let num2Reversed = num2.split('').reverse().join('');
  let index = 0;
  let res = '';
  let carry = false;
  while(index < len1 && index < len2) {
    const char1 = num1Reversed[index];
    const char2 = num2Reversed[index];
    let sum = parseInt(char1) + parseInt(char2);
    if(carry) {
      sum += 1;
      carry = false;
    }
    if(sum >= 10) {
      carry = true;
      sum = sum%10;
    }
    res += sum;
    index++;
  }
  while(index < len1) {
    let cur = num1Reversed[index];
    if(carry) {
      carry = false
      cur =  parseInt(cur)+1;
    }
    if(cur >= 10) {
      cur = cur%10;
      carry = true;
    }
    res += cur;
    index++;
  }
  while(index < len2) {
    let cur = num2Reversed[index];
    if(carry) {
      carry = false
      cur =  parseInt(cur)+1;
    }
    if(cur >= 10) {
      cur = cur%10;
      carry = true;
    }
    res += cur;
    index++;
  }
  if(carry) {
    res += 1;
    carry = false;
  }
  return res.split('').reverse().join('');
}
var multiply = function(num1, num2) {
  if(num1 === '0' || num2 === '0')
    return '0';
  let strArr = [];
  let res = '0';
  for(let i = num1.length-1;i >= 0;i--) {
    strArr.push(
      multiplyStep(num1[i], num1.length-1-i, num2)
    )
  }
    console.log(strArr);
  for(let i = 0;i < strArr.length;i++)  {
    res = addStep(res, strArr[i]);
  }
  return res;
};



相关文章
|
11天前
|
搜索推荐 前端开发 数据可视化
【优秀python web毕设案例】基于协同过滤算法的酒店推荐系统,django框架+bootstrap前端+echarts可视化,有后台有爬虫
本文介绍了一个基于Django框架、协同过滤算法、ECharts数据可视化以及Bootstrap前端技术的酒店推荐系统,该系统通过用户行为分析和推荐算法优化,提供个性化的酒店推荐和直观的数据展示,以提升用户体验。
|
5天前
|
算法
【算法】滑动窗口——找到字符串中所有字母异位词
【算法】滑动窗口——找到字符串中所有字母异位词
|
6天前
|
前端开发 JavaScript Java
【前端学java】详解java中的字符串操作(11)
【8月更文挑战第10天】详解java中的字符串操作
9 3
【前端学java】详解java中的字符串操作(11)
|
12天前
|
搜索推荐 前端开发 算法
基于用户画像及协同过滤算法的音乐推荐系统,采用Django框架、bootstrap前端,MySQL数据库
本文介绍了一个基于用户画像和协同过滤算法的音乐推荐系统,使用Django框架、Bootstrap前端和MySQL数据库构建,旨在为用户提供个性化的音乐推荐服务,提高推荐准确性和用户满意度。
基于用户画像及协同过滤算法的音乐推荐系统,采用Django框架、bootstrap前端,MySQL数据库
|
3天前
|
算法 Java
掌握算法学习之字符串经典用法
文章总结了字符串在算法领域的经典用法,特别是通过双指针法来实现字符串的反转操作,并提供了LeetCode上相关题目的Java代码实现,强调了掌握这些技巧对于提升算法思维的重要性。
|
12天前
|
数据采集 前端开发 算法
基于朴素贝叶斯算法的新闻类型预测,django框架开发,前端bootstrap,有爬虫有数据库
本文介绍了一个基于Django框架和朴素贝叶斯算法开发的新闻类型预测系统,该系统具备用户登录注册、后台管理、数据展示、新闻分类分布分析、新闻数量排名和新闻标题预测等功能,旨在提高新闻处理效率和个性化推荐服务。
|
1月前
|
自然语言处理 算法 搜索推荐
字符串相似度算法完全指南:编辑、令牌与序列三类算法的全面解析与深入分析
在自然语言处理领域,人们经常需要比较字符串,这些字符串可能是单词、句子、段落甚至是整个文档。如何快速判断两个单词或句子是否相似,或者相似度是好还是差。这类似于我们使用手机打错一个词,但手机会建议正确的词来修正它,那么这种如何判断字符串相似度呢?本文将详细介绍这个问题。
205 1
|
1月前
|
数据采集 算法 JavaScript
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
JavaScript字符串搜索涵盖`indexOf`、`includes`及KMP算法。`indexOf`返回子字符串位置,`includes`检查是否包含子字符串。KMP是高效的搜索算法,尤其适合长模式匹配。示例展示了如何在数据采集(如网页爬虫)中使用这些方法,结合代理IP进行安全搜索。代码示例中,搜索百度新闻结果并检测是否含有特定字符串。学习这些技术能提升编程效率和性能。
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
|
15天前
|
算法 C++
惊爆!KPM算法背后的秘密武器:一行代码揭秘字符串最小周期的终极奥义,让你秒变编程界周期大师!
【8月更文挑战第4天】字符串最小周期问题旨在找出字符串中最短重复子串的长度。KPM(实为KMP,Knuth-Morris-Pratt)算法,虽主要用于字符串匹配,但其生成的前缀函数(next数组)也可用于求解最小周期。核心思想是构建LPS数组,记录模式串中每个位置的最长相等前后缀长度。对于长度为n的字符串S,其最小周期T可通过公式ans = n - LPS[n-1]求得。通过分析周期字符串的特性,可证明该方法的有效性。提供的C++示例代码展示了如何计算给定字符串的最小周期,体现了KPM算法在解决此类问题上的高效性。
26 0
|
1月前
|
算法 Java
KMP算法详解及其在字符串匹配中的应用
KMP算法详解及其在字符串匹配中的应用

热门文章

最新文章