算法之字符串问题(第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);
}     


相关文章
|
2月前
|
算法
【优选算法】—— 字符串匹配算法
【优选算法】—— 字符串匹配算法
|
3月前
|
人工智能 算法 测试技术
【动态规划】【字符串】【C++算法】940. 不同的子序列 II
【动态规划】【字符串】【C++算法】940. 不同的子序列 II
|
4月前
|
算法 测试技术 C#
【动态规划】【字符串】C++算法:正则表达式匹配
【动态规划】【字符串】C++算法:正则表达式匹配
|
3月前
|
机器学习/深度学习 算法 C语言
【编码狂想】深度探索C++编程之旅:“数组、字符串、函数与KMP算法解密“
【编码狂想】深度探索C++编程之旅:“数组、字符串、函数与KMP算法解密“
73 0
|
11天前
|
算法
代码随想录算法训练营第五十五天 | LeetCode 583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结
代码随想录算法训练营第五十五天 | LeetCode 583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结
22 1
|
20天前
|
算法
【算法学习--字符串】(不含KMP算法)
【算法学习--字符串】(不含KMP算法)
|
2月前
|
算法 Java
[Java·算法·简单] LeetCode 28. 找出字符串中第一个匹配项的下标 详细解读
[Java·算法·简单] LeetCode 28. 找出字符串中第一个匹配项的下标 详细解读
23 0
|
3月前
|
算法 测试技术 C++
【字符串】【 LCP】【C++算法】2573找出对应 LCP 矩阵的字符串
【字符串】【 LCP】【C++算法】2573找出对应 LCP 矩阵的字符串
|
3月前
|
存储 算法
【编码狂想】LeetCode 字符串和数组篇:挑战算法精髓,深化程序设计基础
【编码狂想】LeetCode 字符串和数组篇:挑战算法精髓,深化程序设计基础
37 0
|
4月前
|
算法 测试技术 C#
【map】【滑动窗口】【字典树】C++算法:最长合法子字符串的长度
【map】【滑动窗口】【字典树】C++算法:最长合法子字符串的长度