力扣-面试题刷题第一天

01.01. 判定字符是否唯一

1、题目

实现一个算法,确定一个字符串 s 的所有字符是否全都不同。

2、初步作答

2.1 思路(错误)

作为从C转过来的 java 选手,做题目第一时间想到的是利用两重 for 循环判断字符串是否相同。

2.2 做法(错误)

使用 for 循环遍历字符串S(这里把字符串当成了数组去操作,实操太少,自己太笨),再嵌套一层 for 循环遍历S,遍历过程中如果遇到相同字符,就返回 false ;循环结束,如果全部遍历结束没有返回 false ,那么就返回 true 。

2.3 代码(错误)

错误解法

class Solution {
    public boolean isUnique(String astr) {
        if(astr == null){
            return true;
        }
        for(int i = 0;i < s.length;i++){
            for(int j = i+1;j < s.length;j++){
                if(astr[i] == astr[j]){
                    return false;
                }
            }
        }
        return true;
    }
}
  • 这里是错误思路的解法,当然就是错误解法啦。

2.4 思考

刷题经历太少导致学过的数据结构算法不知道该怎么使用,只会简单的循环结构叠加(弊端显现啊,属于是)。同时,字符串不是数组,这简直就是语文当英语看,从头错到尾。

3、题目解析

3.1 思路说明

理解到自己的错误就去推翻之前的错误重新再来,那在这里我们还需要多考虑几种情况。

  • 字符串是否为空,空字符串所有字符肯定全部不相同,直接返回 true;

  • 字符串中字符的范围是什么?

    • 1.如果是26个英文字母,就有两种情况需要讨论

      • (1) 只能是小写或大写字母

        • ① 字符串长度大于26直接返回 false;
        • ② 字符串长度小于26时,定义一个大小为26的全0数组。遍历字符串,以'a'=0~'z'=26或'A'=0~'Z'=26 为数组下标,每个字符出现一次相应的数组位加1,如果数组中出现大于1的数时,返回false;如果遍历结束之后,数组所有元素都是0或1,则返回 true。
        • 备注:这里使用两步判断是为了节省运算时间和空间消耗,如果字符串长度大于26,就不用开辟一个数组空间,同时节省了判断的时间消耗。
      • (2) 大小写字母都可以

        • ① 字符串长度大于52直接返回 false;
        • ② 字符串长度小于52时,定义一个大小为52的全0数组。遍历字符串,以'a'=0~'z'=26并且'A'=27~'Z'=52 为数组下标,每个字符出现一次相应的数组位加1,如果数组中出现大于1的数时,返回false;如果遍历结束之后,数组所有元素都是0或1,则返回 true。
    • 2.如果是ASCII码,那么总共范围就是128

    • 3.如果是Unicode,没有字符要求,那么就老老实实排序再判断

  • 本题也可以直接使用字符串索引查询的方法来判断 ( S.charAt() )

  • 题目说明不使用额外的数据结构算法,那么这道题最本质的还是使用位运算(不太会位运算,敲,这就去学习一下)

3.2 代码

3.2.1 使用HashMap

class Solution {
    public boolean isUnique(String astr) {
        if(astr == null){
            return true;
        }
      Map<Character,Integer> map = new HashMap<>();
        for(int i = 0; i< astr.length();i++){
            if(map.containsKey(astr.charAt(i))){
                return false;
            }
            map.put(astr.charAt(i),i);
        }
        return true;
    }
}

3.2.2 使用位运算

class Solution {
    public boolean isUnique(String astr) {
     	int mark = 0;
        for (int i = 0; i < astr.length() ; i++) {
            //移动距离
            int move = (int)astr.charAt(i) - 'a';
           	if ((mark & (1 << move) )!=0){
               	return false;
           	}else {
               	mark |=(1 << move);
           	}
        }
        return true;
}

3.3.3 使用索引比较的方法(初步思路优化)

class Solution {
    public boolean isUnique(String astr) {
        if(astr == null){
            return true;
        }
        for(int i = 0;i < astr.length();i++){
            for(int j = i+1;j < astr.length();j++){
                if(astr.charAt(i) == astr.charAt(j)){
                    return false;
                }
            }
        }
        return true;
    }
}

01.02. 判定是否互为字符重排

1、题目

给定两个字符串 s1s2,请编写一个程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。

2、初步作答

2.1 思路

一个字符串重新排列,仅是字符顺序变化,字符串长度不变,s1 和 s2 长度应一致。排列过程中要记录字符串中字符是否已经使用,使用过的字符不可二次使用。最终,所有字符全部使用,则字符串重排成功。

2.2 做法

  • s2 如果由 s1 重新排列,那么两个字符串长度一定相同。所以,如果字符串长度不同,直接返回false;
  • 新建一个数组,记录字符串中字符使用情况;
  • 我们这里使用 for 循环遍历 s1 中每一个字符,如果字符排列使用,则相应下标数组加 1 ;
  • 比较数组之和与字符串长度是否匹配,匹配则返回 true,反之返回 false;

2.3 代码

class Solution {
    public boolean CheckPermutation(String s1, String s2) {
        if(s1.length() != s2.length()){
            return false;
        }
        int[] num = new int[s1.length()];
        for(int i = 0;i < s1.length();i++){
            for(int j = 0;j < s2.length();j++){
                if(num[j] == 1){
                    continue;
                }
                if(s1.charAt(i) == s2.charAt(j)){
                    num[j] = 1;
                    break;
                }
            }
        }
        int sum = 0;
        for(int m = 0;m < s1.length();m++){
            sum += num[m];
        }
        if(sum == s1.length()){
            return true;
        }else{
            return false;
        }
    }
}
代码运行情况
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:39.1 MB, 在所有 Java 提交中击败了5.27%的用户
通过测试用例:23 / 23

2.4 思考

这里定义了一个数组,导致内存消耗偏大。所以代码优化上,应着重考虑降低内存消耗。

3、题目解析

3.1 字符数组排序比较

class Solution {
    public boolean CheckPermutation(String s1, String s2) {
        char[] s1char = s1.toCharArray();
        Arrays.sort(s1char);
        char[] s2char = s2.toCharArray();
        Arrays.sort(s2char);
        return new String(s1char).equals(new String(s2char));
    }
}

3.2 哈希算法

class Solution {
    public boolean CheckPermutation(String s1, String s2) {
        int len1 = s1.length(), len2 = s2.length();
        if (len1 != len2)
            return false;
        HashMap<Character, Integer> dic = new HashMap<>();
        for (int i = 0; i < len1; i++) {
            dic.put(s1.charAt(i) , dic.getOrDefault(s1.charAt(i), 0) + 1);
        }
        for (int i = 0; i < len2; i++) {
            dic.put(s2.charAt(i) , dic.getOrDefault(s2.charAt(i), 0) - 1);
        }
        for (int val : dic.values()) {
            if (val != 0)
                return false;
        }
        return true;
    }
}
  • 几种方法在内存消耗上都有缺陷,如果有更好的算法,可以告诉我,谢谢

上一篇:搜索与回溯:子集和问题(subsum)


下一篇:知识:高精度加法和减法