算法之字符串问题(第415题字符串相加、第43题字符串相乘、第316题去除重复字母)

简介: 算法之字符串问题(第415题字符串相加、第43题字符串相乘、第316题去除重复字母)

字符串相加(力扣第415题)

题目要求:给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。

你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。

示例

输入:num1 = "11", num2 = "123"
输出:"134"
输入:num1 = "456", num2 = "77"
输出:"533"
输入:num1 = "0", num2 = "0"
输出:"0"

解题思路

这道题目其实就是把字符串的数字进行加法运算,但是不可以直接转成int来进行操作。

那么怎么把它间接转成int呢,这就用到char的特性了,对于char类型如果相减,那么就可以得到int值,例如: int a = '5'-'0'; a的值为5。

这里我们就按照正常的加法运算来做,从右往左每一位相加,保留相加的个位数,然后 /10 得到的数作为下一次相加的数参与进去,直到所有位数加完。如果说两个数长度不一样,那么就往短的前面加0

public static String addStrings(String num1, String num2) {
    //构建一个结果,方便后面拼接
    StringBuffer result = new StringBuffer();
    //定义两个数的最后一位
    int i = num1.length() - 1;
    int j = num2.length() - 1;
    //定义两个数同一个位置相加 /10 的结果
    int carry = 0;
    //这里开始循环,当所有位置相加完毕之后,并且最后一次相加没有大于10将退出循环
    while (i >= 0 || j >= 0 || carry != 0) {
        //当大于等于0当时候取当前当数,否则就是位数不够了用0来补充
        int x = i >= 0 ? num1.charAt(i) - '0' : 0;
        int y = j >= 0 ? num2.charAt(j) - '0' : 0;
        //结果就是相加
        int sum = x + y + carry;
        //大于十的部分记录一下,只保留个位
        result.append(sum % 10);
        carry = sum / 10;
        i--;
        j--;
    }
    return result.reverse().toString();
}

字符串相乘(力扣第43题)

题目要求:给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。

示例

输入: num1 = "2", num2 = "3"
输出: "6"
输入: num1 = "123", num2 = "456"
输出: "56088"

解题思路

这道题目其实就是字符串进行乘法,也是不能直接转成int类型,还是需要用char类型来中转一下。

当然本题也可以像上题一样,直接暴力的按照算术方式进行计算,但是代码量非常大,并且不容易记忆。那么这里我们采用数组的方式来进行计算。

这里需要定义一个用来存储结果的数组,长度为两个数长度相加,毕竟99*999=98901

我们把第一个数作为外层循环,第二个数作为内层循环,然后两两相乘,这里要注意到内层循环每循环一次结果的存放下标要左移。

public String multiply(String num1, String num2) {
    //1.如果两个数都为0,直接返回
    if (num1.equals("0") || num2.equals("0")) {
        return "0";
    }
    //2。定义结果数组
    int[] resultArr = new int[num1.length() + num2.length()];
    //3。遍历第一个数每一个字符
    for (int i = num1.length() - 1; i >= 0; i--) {
        int x = num1.charAt(i) - '0';
        //遍历第二个数每一个字符
        for (int j = num2.length() - 1; j >= 0; j--) {
            int y = num2.charAt(j) - '0';
            //对两个字符进行相乘
            int product = x * y;
            /**
             * 临时数为:相乘结果当前最后一位对应的下标位置的数+相乘结果
             * 然后在把临时数从新进行保存
             * 这里i+j+1为关键
             */
            int temp = resultArr[i + j + 1] + product;
            resultArr[i + j + 1] = temp % 10;
            resultArr[i + j] += temp / 10;
        }
    }
    //如果当前结果数组第一位是0,那么就取1到length-1,如果是1,那么就取0到length-1
    StringBuffer result = new StringBuffer();
    int start = resultArr[0] == 0 ? 1 : 0;
    for (int i = start; i < resultArr.length; i++) {
        result.append(resultArr[i]);
    }
    return result.toString();
}

去除重复字母(力扣第316题)

题目要求:给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对

位置)。

示例

输入:s = "bcabc"
输出:"abc"
输入:s = "cbacdcbc"
输出:"acdb"

数组递归法

解题思路

首先我们要保证最左边的字母是最小的,但是也不完全一定就是a,bacad就不可以,因为b在后面没出现过一次,所以我们有两个条件挑选最左侧值。数值越小越好,但是如果后面没有值重复了,无论多大也都作为最左值。

这里我们先定义一个数组,用来存储26个字母出现的次数

然后我们遍历字符串,然后找到最小的字符,在找的过程中,如果有的值在后面的字符中没出现过(也就是在数组中-1为0),那么就退出循环。

然后获取到这个字符后,截取这个字符后面的字符串进行递归,不过要把重复值去掉。

public String removeDuplicateLetters(String s) {
    if (s.length() == 0) {
        return "";
    }
    //定义一个用来记录最小字母的指针
    int position = 0;
    //定义26个字母次数的数组
    int[] count = new int[26];
    for (int i = 0; i < s.length(); i++) {
        count[s.charAt(i) - 'a']++;
    }
    //遍历字符串
    for (int i = 0; i < s.length(); i++) {
        //当前位置字符如果小于最小字母指针时,指针移动到该最小字母的位置
        if (s.charAt(i) < s.charAt(position)) {
            position = i;
        }
        //当前位置-1为0的时候,代表后面不会出现该字母了,所以该字母必须作为最左侧字母了
        if (--count[s.charAt(i) - 'a'] == 0) {
            break;
        }
    }
    //递归获取每次最小的字母,并且在递归传递参数的时候,要把当前位置前的字符全部删除,当前位置后的字符和当前位置的字符相同的也删掉
    return s.charAt(position) + removeDuplicateLetters(s.substring(position + 1).replaceAll("" + s.charAt(position), ""));
}

使用栈

解题思路

遇到一个新字符,如果比栈顶小,并且在新字符后面还有和栈顶一样的 就把栈顶的字符抛弃

public String removeDuplicateLetters(String s) {
    //定义一个栈
    Stack<Character> stack = new Stack<>();
    //循环字符串
    for (int i = 0; i < s.length(); i++) {
        Character current = s.charAt(i);
        //如果栈中包含这个数直接继续下次循环
        if (stack.contains(current)) {
            continue;
        }
        // 如果栈顶的数大于当前数,并且字符串后边的值不是唯一的
        while (!stack.isEmpty() && stack.peek() > current && s.indexOf(stack.peek(), i) != -1) {
            stack.pop();
        }
        //入栈
        stack.push(current);
    }
    //取栈的值进行拼接
    char chars[] = new char[stack.size()];
    for (int i = 0; i < stack.size(); i++) {
        chars[i] = stack.get(i);
    }
    return new String(chars);
}     


相关文章
|
1月前
|
算法
【算法】滑动窗口——找到字符串中所有字母异位词
【算法】滑动窗口——找到字符串中所有字母异位词
|
1月前
|
算法 Java
掌握算法学习之字符串经典用法
文章总结了字符串在算法领域的经典用法,特别是通过双指针法来实现字符串的反转操作,并提供了LeetCode上相关题目的Java代码实现,强调了掌握这些技巧对于提升算法思维的重要性。
|
2月前
|
自然语言处理 算法 搜索推荐
字符串相似度算法完全指南:编辑、令牌与序列三类算法的全面解析与深入分析
在自然语言处理领域,人们经常需要比较字符串,这些字符串可能是单词、句子、段落甚至是整个文档。如何快速判断两个单词或句子是否相似,或者相似度是好还是差。这类似于我们使用手机打错一个词,但手机会建议正确的词来修正它,那么这种如何判断字符串相似度呢?本文将详细介绍这个问题。
234 1
|
2月前
|
数据采集 算法 JavaScript
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
JavaScript字符串搜索涵盖`indexOf`、`includes`及KMP算法。`indexOf`返回子字符串位置,`includes`检查是否包含子字符串。KMP是高效的搜索算法,尤其适合长模式匹配。示例展示了如何在数据采集(如网页爬虫)中使用这些方法,结合代理IP进行安全搜索。代码示例中,搜索百度新闻结果并检测是否含有特定字符串。学习这些技术能提升编程效率和性能。
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
|
2月前
|
自然语言处理 Rust 算法
【算法】17. 电话号码的字母组合(多语言实现)
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
【算法】17. 电话号码的字母组合(多语言实现)
|
1月前
|
算法 C++
惊爆!KPM算法背后的秘密武器:一行代码揭秘字符串最小周期的终极奥义,让你秒变编程界周期大师!
【8月更文挑战第4天】字符串最小周期问题旨在找出字符串中最短重复子串的长度。KPM(实为KMP,Knuth-Morris-Pratt)算法,虽主要用于字符串匹配,但其生成的前缀函数(next数组)也可用于求解最小周期。核心思想是构建LPS数组,记录模式串中每个位置的最长相等前后缀长度。对于长度为n的字符串S,其最小周期T可通过公式ans = n - LPS[n-1]求得。通过分析周期字符串的特性,可证明该方法的有效性。提供的C++示例代码展示了如何计算给定字符串的最小周期,体现了KPM算法在解决此类问题上的高效性。
49 0
|
2月前
|
算法 Java
KMP算法详解及其在字符串匹配中的应用
KMP算法详解及其在字符串匹配中的应用
|
15天前
|
算法 BI Serverless
基于鱼群算法的散热片形状优化matlab仿真
本研究利用浴盆曲线模拟空隙外形,并通过鱼群算法(FSA)优化浴盆曲线参数,以获得最佳孔隙度值及对应的R值。FSA通过模拟鱼群的聚群、避障和觅食行为,实现高效全局搜索。具体步骤包括初始化鱼群、计算适应度值、更新位置及判断终止条件。最终确定散热片的最佳形状参数。仿真结果显示该方法能显著提高优化效率。相关代码使用MATLAB 2022a实现。
|
15天前
|
算法 数据可视化
基于SSA奇异谱分析算法的时间序列趋势线提取matlab仿真
奇异谱分析(SSA)是一种基于奇异值分解(SVD)和轨迹矩阵的非线性、非参数时间序列分析方法,适用于提取趋势、周期性和噪声成分。本项目使用MATLAB 2022a版本实现从强干扰序列中提取趋势线,并通过可视化展示了原时间序列与提取的趋势分量。代码实现了滑动窗口下的奇异值分解和分组重构,适用于非线性和非平稳时间序列分析。此方法在气候变化、金融市场和生物医学信号处理等领域有广泛应用。
|
16天前
|
资源调度 算法
基于迭代扩展卡尔曼滤波算法的倒立摆控制系统matlab仿真
本课题研究基于迭代扩展卡尔曼滤波算法的倒立摆控制系统,并对比UKF、EKF、迭代UKF和迭代EKF的控制效果。倒立摆作为典型的非线性系统,适用于评估不同滤波方法的性能。UKF采用无迹变换逼近非线性函数,避免了EKF中的截断误差;EKF则通过泰勒级数展开近似非线性函数;迭代EKF和迭代UKF通过多次迭代提高状态估计精度。系统使用MATLAB 2022a进行仿真和分析,结果显示UKF和迭代UKF在非线性强的系统中表现更佳,但计算复杂度较高;EKF和迭代EKF则更适合维数较高或计算受限的场景。