leetcode-383.赎金信

题目

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。

magazine 中的每个字符只能在 ransomNote 中使用一次。

示例 1:

输入:ransomNote = "a", magazine = "b"
输出:false

示例 2:

输入:ransomNote = "aa", magazine = "ab"
输出:false

示例 3:

输入:ransomNote = "aa", magazine = "aab"
输出:true

提示:

1 <= ransomNote.length, magazine.length <= 105
ransomNote 和 magazine 由小写英文字母组成

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/ransom-note

解题思路

解法1:遍历查找
执行用时:7 ms在所有 Java 提交中击败了29.19%的用户
内存消耗:41.7 MB, 在所有 Java 提交中击败了61.50%的用户

解法2:统计比对 识别ransom后统计并用ransom的统计magazine只需要三次循环
执行用时:6 ms, 在所有 Java 提交中击败了29.88%的用户
内存消耗:42 MB, 在所有 Java 提交中击败了26.62%的用户

解法3:统计比对 中统计的改进版,创建一个二维数组来统计字母以及出现的次数
执行用时:21 ms, 在所有 Java 提交中击败了8.42%的用户
内存消耗:42.9 MB在所有 Java 提交中击败了5.01%的用户

解法4,统计比对 的优化版
执行用时:1 ms在所有 Java 提交中击败了99.91%的用户
内存消耗:41.3 MB, 在所有 Java 提交中击败了90.41%的用户

可以得出,解法4>解法1>解法2>解法3

思路一 遍历查找

最简单的思路,将金信中的字符一个一个去杂志里找,找到就做个标记,最后判断是否匹配完全。代码如下:

//解法1:遍历查找
int count = 0;
char[] ransomnoteChar = ransomNote.toCharArray();
char[] magazineChar = magazine.toCharArray();

for (int i = 0; i<ransomNote.length(); i++){
    for (int j = 0; j<magazine.length(); j++){
        if (ransomnoteChar[i]==magazineChar[j]){
            magazineChar[j] = '1';//标记用过
            count++;//记录是否匹配完全
            break;
        }
    }
}
if (count == ransomNote.length()) return true;
else return false;

思路二 统计对比

新建两个数组,统计金信和杂志中的字符,然后进行比对,如果杂志中的字符比金信中对应的字符多或相等,则通过,需要三次循环。代码如下:

char[] ransomnoteChar = ransomNote.toCharArray();
char[] magazineChar = magazine.toCharArray();

//创建26格数组,每格表示一个英文字母
int[] ransomnoteCount = new int[26];
for (int i = 0; i<ransomnoteChar.length; i++){
    switch (ransomnoteChar[i]){
        case 'a': ransomnoteCount[0]++;break;
        case 'b': ransomnoteCount[1]++;break;
        case 'c': ransomnoteCount[2]++;break;
        case 'd': ransomnoteCount[3]++;break;
        case 'e': ransomnoteCount[4]++;break;
        case 'f': ransomnoteCount[5]++;break;
        case 'g': ransomnoteCount[6]++;break;
        case 'h': ransomnoteCount[7]++;break;
        case 'i': ransomnoteCount[8]++;break;
        case 'j': ransomnoteCount[9]++;break;
        case 'k': ransomnoteCount[10]++;break;
        case 'l': ransomnoteCount[11]++;break;
        case 'm': ransomnoteCount[12]++;break;
        case 'n': ransomnoteCount[13]++;break;
        case 'o': ransomnoteCount[14]++;break;
        case 'p': ransomnoteCount[15]++;break;
        case 'q': ransomnoteCount[16]++;break;
        case 'r': ransomnoteCount[17]++;break;
        case 's': ransomnoteCount[18]++;break;
        case 't': ransomnoteCount[19]++;break;
        case 'u': ransomnoteCount[20]++;break;
        case 'v': ransomnoteCount[21]++;break;
        case 'w': ransomnoteCount[22]++;break;
        case 'x': ransomnoteCount[23]++;break;
        case 'y': ransomnoteCount[24]++;break;
        case 'z': ransomnoteCount[25]++;break;
    }
}

int[] magazineCount = new int[26];
for (int i = 0; i<magazineChar.length; i++){
    switch (magazineChar[i]){
        case 'a': magazineCount[0]++;break;
        case 'b': magazineCount[1]++;break;
        case 'c': magazineCount[2]++;break;
        case 'd': magazineCount[3]++;break;
        case 'e': magazineCount[4]++;break;
        case 'f': magazineCount[5]++;break;
        case 'g': magazineCount[6]++;break;
        case 'h': magazineCount[7]++;break;
        case 'i': magazineCount[8]++;break;
        case 'j': magazineCount[9]++;break;
        case 'k': magazineCount[10]++;break;
        case 'l': magazineCount[11]++;break;
        case 'm': magazineCount[12]++;break;
        case 'n': magazineCount[13]++;break;
        case 'o': magazineCount[14]++;break;
        case 'p': magazineCount[15]++;break;
        case 'q': magazineCount[16]++;break;
        case 'r': magazineCount[17]++;break;
        case 's': magazineCount[18]++;break;
        case 't': magazineCount[19]++;break;
        case 'u': magazineCount[20]++;break;
        case 'v': magazineCount[21]++;break;
        case 'w': magazineCount[22]++;break;
        case 'x': magazineCount[23]++;break;
        case 'y': magazineCount[24]++;break;
        case 'z': magazineCount[25]++;break;
    }
}

for (int i = 0; i<26; i++){
    if (ransomnoteCount[i]>magazineCount[i]) return false;
}
return true;

思路三 统计对比–二维数组版

思路二统计的改进版,创建一个二维数组来统计字母以及出现的次数,减少代码量,代码如下:

char[] ransomnoteChar = ransomNote.toCharArray();
char[] magazineChar = magazine.toCharArray();

char[][] ransomnoteCount = new char[ransomnoteChar.length][2];
char[][] magazineCount = new char[magazineChar.length][2];

int point1 = 0;//指针指向已填入的最后一个单元
for (int i = 0; i<ransomnoteChar.length; i++){
    //查看是否已存在
    for (int j = 0; j<ransomnoteCount.length; j++){
        //不存在
        if (j==point1) {
            ransomnoteCount[j][0]=ransomnoteChar[i];
            int c = (int)ransomnoteCount[j][1]-(int)'0';//char和int的转换
            ransomnoteCount[j][1]=(char)(c+1 + '0');
            point1++;
            break;
        }
        //存在
        if (ransomnoteChar[i]==ransomnoteCount[j][0]) {
            int c = (int)ransomnoteCount[j][1]-(int)'0';//char和int的转换
            ransomnoteCount[j][1]=(char)(c+1 + '0');
            break;
        }
    }
}

int point2 = 0;//指针指向已填入的最后一个单元
for (int i = 0; i<magazineChar.length; i++){
    //查看是否已存在
    for (int j = 0; j<magazineCount.length; j++){
        //不存在
        if (j==point2) {
            magazineCount[j][0]=magazineChar[i];
            int c = (int)magazineCount[j][1]-(int)'0';//char和int的转换
            magazineCount[j][1]=(char)(c+1 + '0');
            point2++;
            break;
        }
        //存在
        if (magazineChar[i]==magazineCount[j][0]) {
            int c = (int)magazineCount[j][1]-(int)'0';//char和int的转换
            magazineCount[j][1]=(char)(c+1 + '0');
            break;
        }
    }
}

//对比
for (int i = 0; i<point1; i++){
    for (int j = 0; j<point2; j++){
        if (ransomnoteCount[i][0]==magazineCount[j][0]&&ransomnoteCount[i][1]<=magazineCount[j][1]) break;
        else if (j==point2-1) return false;
    }
}

return true;

思路四 统计对比–优化版

解法3的改进版,与解法3不同的是
1、不需要二维数组,而是利用ascii码建立起数字和字母的关联,减少了一维
2、直接对String进行操作,不需要转换成char数组(利用String.charAt(下标)方法返回字符)。
3、思路改变,只统计杂志的字符,然后用金信来查找,找到就删除一个,直到结束
代码如下:

//记录杂志字符串出现的次数
int[] arr = new int[26];
int temp;//字母对应的编号,0开始
for (int i = 0; i < magazine.length(); i++) {
    temp = magazine.charAt(i) - 'a';
    arr[temp]++;
}
for (int i = 0; i < ransomNote.length(); i++) {
    temp = ransomNote.charAt(i) - 'a';
    //对于金信中的每一个字符都在数组中查找
    //找到相应位减一,否则找不到返回false
    if (arr[temp] > 0) {
        arr[temp]--;
    } else {
        return false;
    }
}
return true;

其他思路

还看到一个统计加减的思路是:
1判断金信和杂志数组长度,如果金信长为false
2如果杂志长,新建一个长度为26的整形数组,先统计杂志和金信相同长度的数组放入一个循环,金信有则加1,杂志有则减1。
3最后判断杂志超出金信的长度的数组,将对应字母都减1.
最后判断此数组内所有的值,如果有值大于0的,则表明金信对应此字母的数量比杂志的多,则false,否则true。

这个思路原作者用的是c++来编写的,速度为最快,在此时间有限就不用java再写一次了。如果大家有空可以去用java实现一下,然后在评论区反馈一下。

作者:xenodochial-faradaywef
链接:https://leetcode.cn/problems/ransom-note/solution/by-xenodochial-faradaywef-nani/
来源:力扣(LeetCode)

总结

其实要想优化代码,现阶段应该从两方面入手:
1、思路(算法),如果算法比较先进的话,节省的时间会是指数级的。
2、工具,在上面好的思路和差的思路对比中,其实也可以发现有很多的工具还待掌握,比如说直接对字符串的操作String.CharAt(),如果没有掌握这种工具的话就会写出上面思路123那样将String转成char[]数组再处理的代码来,所以说将自己能够掌握的工具先掌握清楚也是非常关键的。
3、基础知识,比如说对于Ascii码的理解和运用,还有char和int的转化等等,这类基础知识也是需要非常熟练才能在实战中运用的。

附带贴一下常用的ascii码值;

空格 32
符号 33-47
‘0’-‘9’ 48
符号 58-64
‘A’-‘Z’ 65
符号 91-96
‘a’-‘z’ 97
符号 123-126
DEL 127

革命尚未成功,同志仍需努力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值