算法 字符串

2.字符串

2.1两数相加

题目:

给定两个字符串形式的非负整数 num1num2 ,计算它们的和并同样以字符串形式返回。

1 <= num1.length, num2.length <= 104

num1 和num2都只包含数字 0-9

num1 和num2都不包含任何前导零

输入:num1 = "11", num2 = "123"
输出:"134"

思路:

 123
+999
-----
定义一个用来补位的变量 int add = 0;
定义一个StringBuffer类型用来存储结果 StringBuffer s = new StringBuffer();
第一次计算:
3+9+add = 12 add = 12/10 = 1 s.append(12%10)
第二次计算:
2+9+add = 11+1 = 12 add = 12/10 = 1 s.append(12%10)
第三次计算:
1+9+add = 10+1 = 11 add = 11/10 = 1 s.append(11%10)
由于add != 0 仍然要继续计算
0+0+add = 1 add = 1/10 = 0 s.append(1%10)
s为2211
s.reverse() 进行反转
s为1122

代码

class Solution {
    public String addStrings(String num1, String num2) {
        //定义x,y 均从字符串的末尾获取单个字符 进行+运算
        int x = num1.length()-1;
        int y = num2.length()-1;
        //定义变量 用来存储进位的值
        int add = 0;
        //用来存储相加的结果
        StringBuffer s = new StringBuffer();
        //循环条件:num1.charAt(x)的下标>=0 或 num2.charAt(y) >= 0 或 仍有需要进位的值
        while(x >= 0||y >=0||add != 0){
            int m = x >= 0 ? num1.charAt(x)-'0':0;
            int n = y >= 0 ? num2.charAt(y)-'0':0;
            int result = m+n+add;
            //result/10获取进位的值 例如 3/10 = 0 11/10 = 1
            add = result/10;
            //result%10 获取两个字符相加的和 例如 13%10 = 3 7%10 = 7
            s.append(result%10);
            //字符串num1,num2向前移动一位
            x--;
            y--;
        }
        //反转StringBuffer
        s.reverse();
        return s.toString();
    }
}

2.2 两数相乘

题目:

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

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

1 <= num1.length, num2.length <= 200
num1 和 num2 只能由数字组成。
num1 和 num2 都不包含任何前导零,除了数字0本身。

思路:

    123
*   456
-------
456中的每一位与123进行相乘
定义一个变量carry用来保存进位的值 
定义一个StringBuffer类型的变量temp 用来存储计算得到的值
定义一个String类型的变量res 存放每次乘法的结果 用来结果的相加和返回
int carry = 0;
StringBuffer temp = new StringBuffer();
以num2(456)的字符位数作为循环次数 从后往前循环
for(int i = num2.length()-1;i>=0;i--)
由乘法可知 num2的倒数第2个字符在进行乘法运算时,计算结果的最后一位需要补0 同理倒数第3个字符运算时,结果的最后两位需要补0
     123
*    456
---------
 	 738
 	6150
   49200
写一个for循环,用来补0
循环:
当i = num2.length()-1时 j = 0 条件j<0 不用补0
当i = num2.length()-2时 j = 0 条件j<1 补1个0
当i = num2.length()-3时 j = 0 条件j<2 补2个0
for(int j = 0;j<num2.length()-1-i;j++){
	temp.append("0");
}
拿到num2中各位的值
int n2 = num2.charAt(i)-'0';
循环:num2中某一位的值与num1中各位值相乘 每次的结果再相加
循环条件为 num1中字符的下标>=0 或 进位的值不为0
for(int j = num1.length()-1;j>=0||carry != 0;j--){
	int n1 = j < 0 ? 0 : num1.charAt(j) - '0';
	//(相乘后+进位值)%10 得到该位的值
    int product = (n1 * n2 + carry) % 10;
    temp.append(product);
    //进位的值
    carry = (n1 * n2 + carry) / 10;
}
// 将当前结果与新计算的结果求和作为新的结果
res = addStrings(res, temp.reverse().toString()); 

解法

/**
    * 计算形式
    *    num1
    *  x num2
    *  ------
    *  result
    */
class Solution {
    public String multiply(String num1, String num2) {
        if(num1.equals("0") || num2.equals("0")){
            return "0";
        }
        //存放返回的结果
        String res = "0";
        //以num2的字符数作为循环次数    
        for(int i = num2.length()-1;i>=0;i--){
            //用来保存进位的值
            int carry = 0;
            StringBuffer temp = new StringBuffer();
            //补0 例如123 * 23 23中的2和123相乘 结果中最后一位为0
            //num2中 最后一位不需要补0 倒数第2位补1个0 倒数第3位补2个0 ...
            for(int j = 0;j<num2.length()-1-i;j++){
                temp.append("0");
            }
            //拿到num2中各位的值
            int n2 = num2.charAt(i)-'0';
            //num2中某一位的值与num1中各位值相乘
            for(int j = num1.length()-1;j>=0||carry != 0;j--){
                int n1 = j < 0 ? 0 : num1.charAt(j) - '0';
                int product = (n1 * n2 + carry) % 10;
                temp.append(product);
                //进位的值
                carry = (n1 * n2 + carry) / 10;
            }
            // 将当前结果与新计算的结果求和作为新的结果
            res = addStrings(res, temp.reverse().toString()); 
        }
        return res;
    }
        public String addStrings(String num1, String num2) {
        int x = num1.length()-1;
        int y = num2.length()-1;
        int add = 0;
        StringBuffer s = new StringBuffer();
        while(x >= 0||y >=0||add != 0){
            int m = x >= 0 ? num1.charAt(x)-'0':0;
            int n = y >= 0 ? num2.charAt(y)-'0':0;
            int result = m+n+add;
            add = result/10;
            s.append(result%10);
            x--;
            y--;
        }
        s.reverse();
        return s.toString();
    }       
}

2.3 去除重复字母

题目:

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

输入:s = "bcabc"
输出:"abc"
输入:s = "cbacdcbc"
输出:"acdb"
  • 1 <= s.length <= 104
  • s 由小写英文字母组成

思路:

字典序即 abcdefg...字母的顺序
用栈来存放去重后的字符
定义一个boolean[] b 用来表示 某个字符是否在栈中
例如 b['a'] = true 表示该字符在栈中
特殊情况,栈顶字符的字典序大于 当前循环遍历的字符 但栈顶字符在整个字符串中只有一个 所以栈顶字符放在前边

解法

class Solution {
    public String removeDuplicateLetters(String s) {
        //用来标志stack中是否已有此字符
        boolean[] b = new boolean[256];
        //用来计算s中此字符出现的次数
        int[] counts = new int[256];
        Stack<Character> stack = new Stack<>();
        char[] c = s.toCharArray();
        //计算得到每个字符出现的次数
        for(int i = 0;i<c.length;i++){
            if(counts[c[i]] == 0){
                counts[c[i]] = 1;
            } else {
                counts[c[i]] = counts[c[i]]+1;
            }
        }
        for(int i = 0;i<c.length;i++){
            char cc = c[i];
            //每遍历一个字符 字符出现的次数-1
            counts[cc]--;
            //该字符已在栈中,下一轮循环
            if(b[cc]){
                continue;
            } else {
                //遍历栈,栈顶字符字典序 > 当前字符字典序 如果栈顶字符出现次数为0 结束循环 否则 栈顶出栈 标记出栈字符不在栈中
                while(!stack.isEmpty() && stack.peek() > cc){
                    if(counts[stack.peek()] == 0){
                        break;
                    }
                    b[stack.pop()] = false;
                }
            }
            stack.push(cc);
            b[cc] = true;
        }
        StringBuffer str = new StringBuffer();
        while(!stack.isEmpty()){
            str.append(stack.peek());
            stack.pop();
        }
        return str.reverse().toString();
    }
}
2.4 使括号有效的最少添加(921)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GhfAmvQ0-1651729393164)(D:\markdown文件\算法\算法图片\QQ截图20220411103634.png)]

思路:

判断参数 需要添加多少个(或),设字符串成为有效的括号
例如 参数()) 需要添加一个(  变成(()) 或 ()() 不关心添加到哪个位置 只需要返回添加符号的个数
将字符串转成char[] 遍历数组 定义n1,n2分别记录要添加的(和)的数量
发现一个'(' 则n2+1( 需要一个')' )
发现一个')' n2-1 当n2 = -1时 说明'(' 不够 需要添加一个'(' n1+1 添加完一个'(' 左右括号抵消 n2 = 0 最终返回结果为n1+n2

解法

class Solution {
    public int minAddToMakeValid(String s) {
        int n1 = 0;
        int n2 = 0;
        char[] c = s.toCharArray();
        for(char cc: c){
            //如果当前字符为( 则需要的)数量+1
            if(cc == '('){
                n2++;
            }
            //如果当前字符为) 则需要的)数量-1
            if(cc == ')'){
                n2--;
                //如果当前)数量 = -1 说明需要(的数量+1 由于左右()抵消 所以)需要的数量置为0
                if(n2 == -1){
                    n2 = 0;
                    n1++;
                }
            }
        }
        return n1+n2;
    }
}

2.5 平衡括号字符串的最少插入次数(1541)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C1MmcmBU-1651729393165)(D:\markdown文件\算法\算法图片\QQ截图20220411104419.png)]

思路:

()) 一个'(' 对应两个')' 称为平衡字符串
给定一个字符串 返回添加多少个字符,使其成为平衡字符串
例如 )( 返回结果为4 -> ())())
将字符串 转成char[] 遍历数组 定义n1 n2记录要添加'(' 和 ‘)’的数量
当遇到'('时 n2+=2 此时需要检查n2的数量 由于'('对应两个‘)’ 所以‘)’的需求量为偶数 如果此时‘)’的需求量为奇数时 需要再插入一个‘)’
if(n2 % 2 == 1){
	n1++;
	n2--;
}
当遇到‘)’时 n2-- 当n2 = -1时 说明‘)’太多了 需要插入一个'(' 同时n2 = 1
if(c[i] == ')'){
    n2--;
    if(n2 == -1){
        n1++;
        n2 = 1;
    }
}

解法

class Solution {
    public int minInsertions(String s) {
        int n1 = 0;
        int n2 = 0;
        char[] c = s.toCharArray();
        for(int i = 0;i<c.length;i++){
            if(c[i] == '('){
                n2+=2;
                //如果对于)的需求量为奇数 由于(对应两个) 所以)的需求量为偶数 当)需求量为奇数时,需要插入一个)
                if(n2 %2 == 1){
                    n1++;
                    n2--;
                }
            }
            if(c[i] == ')'){
                n2--;
                //说明)太多了
                if(n2 == -1){
                    //插入一个(
                    n1++;
                    //由于( 对应两个) 原本)数量为-1 添加一个( 后 )数量修改为1
                    n2 = 1;
                }
            }
        }
        return n2+n1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值