力扣简单题

news2025/1/14 18:13:20

目录

9、回文数

13、罗马数字转整数 

14、最长公共前缀 

20、有效的括号

58、最后一个单词的长度

 66、加一

69、x的平方根 

94、二叉树的中序遍历 

100、相同的树 

202、快乐数

205、同构字符串

242、有效的字母异位词

258、各位相加

268、丢失的数字 

290、单词规律

 326、3的幂

 338、比特位计数

342、4的幂

344、反转字符串

349、两个数组的交集

 367、有效的完全平方数

387、字符串的第一个唯一字符

389、找不同

 392、判断子序列

409、最长回文串

412、Fizz Buzz

414、第三大的数

 434、字符串中的单词数


9、回文数

 我的答案:(普通遍历)

class Solution {
    public boolean isPalindrome(int x) {
        String s=((Integer)x).toString();
        for(int i=0,j=s.length()-1;i<j;i++,j--){
            if(s.charAt(i)!=s.charAt(j)){
                return false;
            }
        }
        return true;
    }
}

官方答案:

思路一:反转整个数字,如果反转后的数字溢出那它一定不是回文数,因为回文数反转后等于它本身

思路二:反转一半的数字和剩下的一半作比较,关键在于分两种情况(奇数个数字和偶数个数字)

class Solution {
    public boolean isPalindrome(int x) {
        // 特殊情况:
        // 1、当 x < 0 时,x 不是回文数。
        // 2、如果数字的最后一位是 0,为了使该数字为回文,则其第一位数字也应该是 0,只有 0 满足这一属性
        if (x < 0 || (x % 10 == 0 && x != 0)) {
            return false;
        }

        int revertedNumber = 0;
        while (x > revertedNumber) {//将数字的一半反转过来和剩下的一半比较,分奇数个数字和偶数个数字两种情况
            revertedNumber = revertedNumber * 10 + x % 10;
            x /= 10;
        }

        // 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。
        // 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,
        // 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。
        return x == revertedNumber || x == revertedNumber / 10;
    }
}

13、罗马数字转整数 

 

我的答案:

class Solution {
    public int romanToInt(String s) {
        int sum=0;
        int[] arr=new int[s.length()];
        for(int i=0,j=0;i<s.length();i++){//把罗马数字转成阿拉伯数字,后面再做细致判断
            switch(s.charAt(i)){
                case 'I':
                    arr[j++]=1;
                    break;
                case 'V':
                    arr[j++]=5;
                    break;
                case 'X':
                    arr[j++]=10;
                    break;
                case 'L':
                    arr[j++]=50;
                    break;
                case 'C':
                    arr[j++]=100;
                    break;
                case 'D':
                    arr[j++]=500;
                    break;
                case 'M':
                    arr[j++]=1000;
                    break;
            }
        }
        if(s.length()==1) return arr[0];//单个罗马字符,直接返回,长度不够,不能参加下面的for循环
        int i=0;
        for(i=0;i<arr.length-1;){
            if(arr[i]<arr[i+1]){
                if(arr[i]==1&&arr[i+1]==5){
                    sum+=4;
                    i=i+2;
                    continue;
                }else if(arr[i]==1&&arr[i+1]==10){
                    sum+=9;
                    i=i+2;
                    continue;
                }else if(arr[i]==10&&arr[i+1]==50){
                    sum+=40;
                    i=i+2;
                    continue;
                }else if(arr[i]==10&&arr[i+1]==100){
                    sum+=90;
                    i=i+2;
                    continue;
                }else if(arr[i]==100&&arr[i+1]==500){
                    sum+=400;
                    i=i+2;
                    continue;
                }else if(arr[i]==100&&arr[i+1]==1000){
                    sum+=900;
                    i=i+2;
                    continue;
                }
            }
            sum+=arr[i];//arr[i]不属于特例,直接加
            i++;
            
        }
        if(i==s.length()-1){//数组的倒数两个是六个特例之一,那应该是i==s.length(),否则刚好数组剩下一个单独的没有加进去
            sum+=arr[s.length()-1];
        }
        return sum;
    }
}

 

官方答案:模拟

思路:如果小的数字在大的数字的左边,则减去小值,否则加上小值。

class Solution {
    Map<Character, Integer> symbolValues = new HashMap<Character, Integer>() {{//哈希映射,键为字符,值为数值大小
        put('I', 1);
        put('V', 5);
        put('X', 10);
        put('L', 50);
        put('C', 100);
        put('D', 500);
        put('M', 1000);
    }};

    public int romanToInt(String s) {
        int ans = 0;
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            int value = symbolValues.get(s.charAt(i));
            if (i < n - 1 && value < symbolValues.get(s.charAt(i + 1))) {//小的数在大的左边,做减法
                ans -= value;
            } else {//小的在大的右边,做加法
                ans += value;
            }
        }
        return ans;
    }
}

14、最长公共前缀 

我的答案: 

class Solution {
    public String longestCommonPrefix(String[] strs) {
        String s=strs[0];//初始化存储公共前缀的字符串
        for(int i=1;i<strs.length;i++){
            
            if(s.length()==0||strs[i].length()==0||(s.charAt(0)!=strs[i].charAt(0))) return "";//字符数组中包含空串或者第一个字符就不相同了,一定没有公共前缀
            int j=0;
            for(;j<strs[i].length()&&j<s.length();){
                if(s.charAt(j)==strs[i].charAt(j)){
                    j++;
                }else{
                        break;//因为相同位置的字符不等,而跳出循环
                }                
            }
            s=strs[i].substring(0,j);//两个字符串比较完毕,更新公共前缀
        }
        return s;
    }
}

 官方答案:

法一:横向扫描

思路:

依次遍历字符串数组串的每个字符串,不断地更新最长公共前缀。

若尚未遍历完,最长公共前缀已经是空串,则直接返回空串。

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) {//特殊情况,特殊处理
            return "";
        }
        String prefix = strs[0];//prefix是最长公共前缀字符串
        int count = strs.length;//字符串数组的长度
        for (int i = 1; i < count; i++) {
            prefix = longestCommonPrefix(prefix, strs[i]);//维护最长公共前缀字符串
            if (prefix.length() == 0) {//可能还没遍历完,但最长公共前缀是空串,直接返回
                break;
            }
        }
        return prefix;
    }

    public String longestCommonPrefix(String str1, String str2) {
        int length = Math.min(str1.length(), str2.length());//遍历完最短的字符串即可
        int index = 0;
        while (index < length && str1.charAt(index) == str2.charAt(index)) {//获取最长公共前缀最后面一个字符的下标
            index++;
        }
        return str1.substring(0, index);
    }
}

 法二:纵向扫描

从前往后遍历所有字符串上的每一列,比较相同列上的字符是否相同。

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) {
            return "";
        }
        int length = strs[0].length();//维护最长公共前缀的长度,初始时是第一个字符串的长度,再慢慢削减
        int count = strs.length;//字符串数组的长度
        for (int i = 0; i < length; i++) {
            char c = strs[0].charAt(i);//遍历第一个字符串的每个字符,与后面所有的字符串同列的字符做比较
            for (int j = 1; j < count; j++) {
                if (i == strs[j].length() || strs[j].charAt(i) != c) {
                    return strs[0].substring(0, i);//截取前i个字符返回
                }
            }
        }
        return strs[0];//第一个字符串整个都是最长公共前缀
    }
}

法三:分治

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) {
            return "";
        } else {
            return longestCommonPrefix(strs, 0, strs.length - 1);//递归
        }
    }

    public String longestCommonPrefix(String[] strs, int start, int end) {
        if (start == end) {//子问题已经分解到最小规模了,开始返回
            return strs[start];
        } else {//继续分解字符串数组
            int mid = (end - start) / 2 + start;
            String lcpLeft = longestCommonPrefix(strs, start, mid);
            String lcpRight = longestCommonPrefix(strs, mid + 1, end);
            return commonPrefix(lcpLeft, lcpRight);//获取分解出的两个子问题的公共前缀
        }
    }

    public String commonPrefix(String lcpLeft, String lcpRight) {//返回两个子问题的字符串的最长公共前缀
        int minLength = Math.min(lcpLeft.length(), lcpRight.length());       
        for (int i = 0; i < minLength; i++) {
            if (lcpLeft.charAt(i) != lcpRight.charAt(i)) {
                return lcpLeft.substring(0, i);
            }
        }
        return lcpLeft.substring(0, minLength);
    }
}

 法四:二分查找 

最长公共前缀的长度不会超过字符串数组中的最短字符串的长度。在最短长度的范围内通过二分查找得到最长公共前缀的长度。

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) {
            return "";
        }
        int minLength = Integer.MAX_VALUE;//赋给一个最大值做初始化
        for (String str : strs) {//遍历字符串数组,得到最短的字符串长度
            minLength = Math.min(minLength, str.length());
        }
        int low = 0, high = minLength;
        while (low < high) {
            int mid = (high - low + 1) / 2 + low;
            if (isCommonPrefix(strs, mid)) {//递归
                low = mid;
            } else {
                high = mid - 1;
            }
        }
        return strs[0].substring(0, low);
    }

    public boolean isCommonPrefix(String[] strs, int length) {
        String str0 = strs[0].substring(0, length);
        int count = strs.length;
        for (int i = 1; i < count; i++) {
            String str = strs[i];
            for (int j = 0; j < length; j++) {
                if (str0.charAt(j) != str.charAt(j)) {
                    return false;
                }
            }
        }
        return true;
    }
}

20、有效的括号

 我的答案:

class Solution {
    public boolean isValid(String s) {
        if(s.length()%2==1) return false;
        char[] c=new char[s.length()];
        for(int i=0,j=0;i<s.length();i++){
            if(s.charAt(i)=='('||s.charAt(i)=='{'||s.charAt(i)=='['){
                c[j++]=s.charAt(i);
                if(j>s.length()/2||i==s.length()-1)//左括号的个数超过一半了,一定没有足够的右括号来匹配
                    //最后一个一定不是左括号
                    return false;
            }else if(j==0){//字符串的第一个一定不是右括号
                return false;
            }else{
                switch(c[--j]){
                    case '(':
                        if(s.charAt(i)!=')')
                            return false;
                        break;
                    case '{':
                        if(s.charAt(i)!='}')
                            return false;
                        break;
                    case '[':
                        if(s.charAt(i)!=']')
                            return false;
                        break;
                }
            }
        }
        
        return true;
    }
}

官方答案:栈

class Solution {
    public boolean isValid(String s) {
        int n = s.length();
        if (n % 2 == 1) {//字符串的长度为奇数,则一定有一个括号没有伴
            return false;
        }

        Map<Character, Character> pairs = new HashMap<Character, Character>() {{//哈希映射,键为右括号,值为左括号
            put(')', '(');
            put(']', '[');
            put('}', '{');
        }};
        Deque<Character> stack = new LinkedList<Character>();
        for (int i = 0; i < n; i++) {
            char ch = s.charAt(i);
            if (pairs.containsKey(ch)) {//遇到了右括号
                if (stack.isEmpty() || stack.peek() != pairs.get(ch)) {//读取栈顶的左括号和哈希映射的右括号(键)对应的左括号(值)进行对比
                    return false;
                }
                stack.pop();//匹配成功,删除栈顶元素
            } else {
                stack.push(ch);//将遇到的左括号放入栈顶
            }
        }
        return stack.isEmpty();
    }
}

 网友答案:

class Solution {
    public boolean isValid(String s) {
        //执行用时:1 ms, 在所有 Java 提交中击败了98.35%的用户
        Stack<Character> stack=new Stack<>();
        for(int i=0;i<s.length();i++){
            char c=s.charAt(i);
            switch(c){
                case '(':
                case '[':
                case '{':{
                    stack.push(c);
                    break;
                }
                case ')':{
                    if(stack.isEmpty() || stack.pop()!='(') return false;
                    break;
                }
                case ']':{
                    if(stack.isEmpty() || stack.pop()!='[') return false;
                    break;
                }
                case '}':{
                    if(stack.isEmpty() || stack.pop()!='{') return false;
                    break;
                }
            }
        }
        return stack.isEmpty() ? true : false;
    }
}

58、最后一个单词的长度

我的答案:

class Solution {
    public int lengthOfLastWord(String s) {
        String[] s2=s.split("\s+");
        return s2[s2.length-1].length();
    }
}

  官方答案:反向遍历

class Solution {
    public int lengthOfLastWord(String s) {
        int index = s.length() - 1;
        while (s.charAt(index) == ' ') {//字符串后面可能有多个空格,得找到最后一个字母的下标
            index--;
        }
        int wordLength = 0;
        while (index >= 0 && s.charAt(index) != ' ') {//从后往前遍历,直到到达起始位置或者遇到空格为止
            wordLength++;
            index--;
        }
        return wordLength;
    }
}

 66、加一

我的答案:

class Solution {
    public int[] plusOne(int[] digits) {
        int len=digits.length;
        if(digits[len-1]!=9){//字符数组的最后一位不是9,直接加1后,数组长度不变
            digits[len-1]+=1;
            return digits;
        }

        int i=len-1;
        for(;i>=0;i--){//从后往前计算9的个数
            if(digits[i]!=9){
                break;
            }
        }

        if(i>=0){
            digits[i]+=1;//最后一个不为9的数字加1
            for(i=i+1;i<len;i++){//后面的数字全部置为0
                digits[i]=0;
            }
            return digits;
        }

        int[] arr=new int[len+1];
        arr[0]=1;
        for(int j=1;j<len+1;j++){//数组全是9
            arr[j]=0;
        }
        return arr;
    }
}
/**
注意:
如果把字符数组转成整数后再加1,然后再转回字符数组。
这种解法不行,因为转成整数时,数字的大小可能会超出2^31-1,这个数字就废了,没法进行正常运算。
 */

 

官方答案:

class Solution {
    public int[] plusOne(int[] digits) {
        int n = digits.length;
        for (int i = n - 1; i >= 0; --i) {
            if (digits[i] != 9) {//找到第一个不为9的元素,将其加一并将后续所有元素置0
                ++digits[i];
                for (int j = i + 1; j < n; ++j) {
                    digits[j] = 0;
                }
                return digits;
            }
        }

        // digits 中所有的元素均为 9
        int[] ans = new int[n + 1];
        ans[0] = 1;
        return ans;
    }
}

69、x的平方根 

我的答案:

class Solution {
    public int mySqrt(int x) {
        if(x==1) return 1;
        if(x>=2147395600) return 46340;
        for(int i=1;i<x;i++){
            if(i*i<=x&&(i+1)*(i+1)>x){
                return i;
            }
        }
        return 0;
    }
}

 官方答案:

法一:袖珍计算器算法

class Solution {
    public int mySqrt(int x) {
        if (x == 0) {
            return 0;
        }
        int ans = (int) Math.exp(0.5 * Math.log(x));
        return (long) (ans + 1) * (ans + 1) <= x ? ans + 1 : ans;//因为上面把浮点型强转为整型时会存在误差,
    }
}

法二:二分查找 

在【0,x】范围内二分查找算术平方根

class Solution {
    public int mySqrt(int x) {
        int l = 0, r = x, ans = -1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if ((long) mid * mid <= x) {
                ans = mid;
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
        return ans;
    }
}

94、二叉树的中序遍历 

 

 我的答案:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    List<Integer> list=new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {   
         if(root==null){
             return list;
         }
                 
        if(root.left!=null){
            inorderTraversal(root.left); 
         }
         list.add(root.val);
        if(root.right!=null){
            inorderTraversal(root.right); 
         }
        return list;
    }
}

 

官方答案:

法一:递归 

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        inorder(root, res);
        return res;
    }

    public void inorder(TreeNode root, List<Integer> res) {
        if (root == null) {
            return;
        }
        inorder(root.left, res);
        res.add(root.val);
        inorder(root.right, res);
    }
}

 法二:迭代

递归的时候隐式地维护了一个栈,而我们在选代的时候需要显式地将这个栈模拟出来,其他都相同。

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        Deque<TreeNode> stk = new LinkedList<TreeNode>();
        while (root != null || !stk.isEmpty()) {
            while (root != null) {//把当前结点的左结点都压入栈中
                stk.push(root);
                root = root.left;
            }
            root = stk.pop();//弹出栈顶元素
            res.add(root.val);//加入链表
            root = root.right;//把它的右结点当成当前结点
        }
        return res;
    }
}

 法三:Morris 中序遍历

假设当前遍历到的节点为x,将x的左子树中最右边的节点的右孩子指向x,这样在左子树遍历完成后我们通过这个指向走回了x,且能通过这个指向知晓我们已经遍历完成了左子树  而不用再通过栈来维护。

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        TreeNode predecessor = null;

        while (root != null) {
            if (root.left != null) {
                // predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止
                predecessor = root.left;
                while (predecessor.right != null && predecessor.right != root) {
                    predecessor = predecessor.right;
                }
                
                // 让 predecessor 的右指针指向 root,继续遍历左子树
                if (predecessor.right == null) {
                    predecessor.right = root;
                    root = root.left;
                }
                // 说明左子树已经访问完了,我们需要断开链接
                else {
                    res.add(root.val);
                    predecessor.right = null;
                    root = root.right;
                }
            }
            // 如果没有左孩子,则直接访问右孩子
            else {
                res.add(root.val);
                root = root.right;
            }
        }
        return res;
    }
}

100、相同的树 

我的答案:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        //递归返回boolean值的两种情况
        //1、两个根节点都走到尽头了,返回true
        //2、在递归过程中两个根节点的值不相同或者其中一个为根节点为空,返回false
        if(p==null&&q==null){
            return true;
        }else if(p==null||q==null||p.val!=q.val){
            return false;
        }    
        return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
    }
}
/**
做这道题时,最困惑的点在于在左、右子树的递归上面已经写完了判断条件,
但是最后下面必须要有一个返回值,这个返回值无论是写true还是false,都是错的,
最后看了官方答案,才知道返回左子树和右子树递归结果的与运算 */

 

 官方答案:

法一:深度优先搜索

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if (p == null && q == null) {
            return true;
        } else if (p == null || q == null) {
            return false;
        } else if (p.val != q.val) {
            return false;
        } else {
            return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
        }
    }
}

法二:广度优先搜索 

使用两个队列分别存储两个二叉树的节点,比较队列中取出的节点的值是否相同。

取出的结点的左右子节点都不为空,先加左,再加右。。。

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if (p == null && q == null) {
            return true;
        } else if (p == null || q == null) {
            return false;
        }
        Queue<TreeNode> queue1 = new LinkedList<TreeNode>();
        Queue<TreeNode> queue2 = new LinkedList<TreeNode>();
        queue1.offer(p);
        queue2.offer(q);
        while (!queue1.isEmpty() && !queue2.isEmpty()) {
            TreeNode node1 = queue1.poll();
            TreeNode node2 = queue2.poll();
            if (node1.val != node2.val) {
                return false;
            }
            TreeNode left1 = node1.left, right1 = node1.right, left2 = node2.left, right2 = node2.right;
            if (left1 == null ^ left2 == null) {//两个节点的子节点结构不同
                return false;
            }
            if (right1 == null ^ right2 == null) {
                return false;
            }
            if (left1 != null) {
                queue1.offer(left1);
            }
            if (right1 != null) {
                queue1.offer(right1);
            }
            if (left2 != null) {
                queue2.offer(left2);
            }
            if (right2 != null) {
                queue2.offer(right2);
            }
        }
        return queue1.isEmpty() && queue2.isEmpty();
    }
}

202、快乐数

我的答案:

class Solution {
    public boolean isHappy(int n) {
        if(n==1) return true;
        int sum=0;
        while(n!=1){
            while(n!=0){
                sum+=(int)Math.pow(n%10,2);//取余获取个位数
                n=n/10;//削掉个位数
            }
            if(sum==4){
                return false;
            }
            n=sum;
            sum=0;
        }
        return true;

        
    }
}
//所有不快乐数的数位平方和计算,最后都会进入 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4 的循环中

 

官方答案:

法一:用哈希集合检测循环

class Solution {
    private int getNext(int n) {
        int totalSum = 0;
        while (n > 0) {
            int d = n % 10;
            n = n / 10;
            totalSum += d * d;
        }
        return totalSum;
    }

    public boolean isHappy(int n) {
        Set<Integer> seen = new HashSet<>();
        while (n != 1 && !seen.contains(n)) {//有数字重复出现,证明这个不是快乐数
            seen.add(n);
            n = getNext(n);
        }
        return n == 1;
    }
}

 法二:快慢指针法

通过反复调用getNext(n)得到的链是一个隐式的链表。隐式意味看我们没有实际的链表节点和指针,但数据仍然形成链表结构。从而将问题转换为检测一个链表是否有环。

class Solution {

     public int getNext(int n) {
        int totalSum = 0;
        while (n > 0) {
            int d = n % 10;
            n = n / 10;
            totalSum += d * d;
        }
        return totalSum;
    }

    public boolean isHappy(int n) {
        int slowRunner = n;
        int fastRunner = getNext(n);
        while (fastRunner != 1 && slowRunner != fastRunner) {
            slowRunner = getNext(slowRunner);//慢跑者一次走一步
            fastRunner = getNext(getNext(fastRunner));//快跑者一次走两步
        }
        return fastRunner == 1;
    }
}

法三:数学 

有一个循环:4→16→37→58→89→145→42→20→4。所有不是快乐数的数字都在进入这个循环的链上,或者在进入1的链上。因此,我们可以硬编码一个包含这些数字的散列集,如果我们达到其中一个数字,那么我们就知道在循环中。

class Solution {

    private static Set<Integer> cycleMembers =
        new HashSet<>(Arrays.asList(4, 16, 37, 58, 89, 145, 42, 20));

    public int getNext(int n) {
        int totalSum = 0;
        while (n > 0) {
            int d = n % 10;
            n = n / 10;
            totalSum += d * d;
        }
        return totalSum;
    }


    public boolean isHappy(int n) {
        while (n != 1 && !cycleMembers.contains(n)) {
            n = getNext(n);
        }
        return n == 1;
    }
}

205、同构字符串

我的答案:

class Solution {
    public boolean isIsomorphic(String s, String t) {
        List<Integer> list=new ArrayList<>();
        List<Character> list2=new ArrayList<>();
        for(int i=0;i<127;i++){//0-127的ascii码
            for(int j=0;j<s.length();j++){
                if(s.charAt(j)==(char)i){
                    list.add(j);
                    if(t.charAt(j)!=t.charAt(list.get(0))||list2.contains(t.charAt(j))){
                        //1、相同字符不能映射到不同的字符
                        //2、不同的字符不能映射到相同的字符
                        return false;
                    }
                }
                
            }
            if(!list.isEmpty()){
                list2.add(t.charAt(list.get(0)));
            }
            list.clear();
        }
        return true;
    }
}

 

官方答案:哈希表

维护两张哈希表,

第一张哈希表s2以s中字符为键,映射至t的字符为值,

第二张哈希表t2以t中字符为键,映射至s的字符为值。

从左至右遍历两个字符串的字符,不断更新两张哈希表

  • 如果出现冲突(即当前下标index对应的字符s[index]已经存在映射且不为t[index]或当前下标index对应的字符t[index]已经存在映射且不为s[index])时说明两个字符串无法构成同构,返回false。
  • 如果遍历结束没有出现冲突,则表明两个字符串是同构的,返回true即可
class Solution {
    public boolean isIsomorphic(String s, String t) {
        Map<Character, Character> s2t = new HashMap<Character, Character>();
        Map<Character, Character> t2s = new HashMap<Character, Character>();
        int len = s.length();
        for (int i = 0; i < len; ++i) {
            char x = s.charAt(i), y = t.charAt(i);
            if ((s2t.containsKey(x) && s2t.get(x) != y) || (t2s.containsKey(y) && t2s.get(y) != x)) {
                return false;
            }
            s2t.put(x, y);
            t2s.put(y, x);
        }
        return true;
    }
}

242、有效的字母异位词

 我的答案:

法一:

class Solution {
    public boolean isAnagram(String s, String t) {
        if(s.length()!=t.length()){
            return false;
        }
        char[] c1=s.toCharArray();
        Arrays.sort(c1);
        char[] c2=t.toCharArray();
        Arrays.sort(c2);
        s=String.valueOf(c1);
        t=String.valueOf(c2);
        if(!s.equals(t)){
            return false;
        }
        return true;
    }
}

 法二:

class Solution {
    public boolean isAnagram(String s, String t) {
        if(s.length()!=t.length()){
            return false;
        }
        char[] c1=s.toCharArray();
        Arrays.sort(c1);
        char[] c2=t.toCharArray();
        Arrays.sort(c2);
        for(int i=0;i<s.length();i++){
            if(c1[i]!=c2[i]){
                return false;
            }
        }
        return true;
    }
}

官方答案:

法一:排序

class Solution {
    public boolean isAnagram(String s, String t) {
        if (s.length() != t.length()) {
            return false;
        }
        char[] str1 = s.toCharArray();
        char[] str2 = t.toCharArray();
        Arrays.sort(str1);
        Arrays.sort(str2);
        return Arrays.equals(str1, str2);
    }
}

法二:哈希表 

t 是 s 的异位词等价于「两个字符串中字符出现的种类和次数均相等」

class Solution {
    public boolean isAnagram(String s, String t) {
        if (s.length() != t.length()) {
            return false;
        }
        int[] table = new int[26];
        for (int i = 0; i < s.length(); i++) {//记录字符串s中字符出现的频次
            table[s.charAt(i) - 'a']++;
        }
        for (int i = 0; i < t.length(); i++) {//遍历字符串t,减去table 中对应的频次
            table[t.charAt(i) - 'a']--;
            if (table[t.charAt(i) - 'a'] < 0) {
                return false;
            }
        }
        return true;
    }
}

258、各位相加

我的答案:

class Solution {
    public int addDigits(int num) {
        
        while(num/10!=0){
            int sum=0;
            while(num!=0){
                sum+=(num%10);
                num=num/10;
            }
            num=sum;
        }
        return num;
    }
}

官方答案:

法一:模拟

class Solution {
    public int addDigits(int num) {
        while (num >= 10) {
            int sum = 0;
            while (num > 0) {
                sum += num % 10;
                num /= 10;
            }
            num = sum;
        }
        return num;
    }
}

法二:数学 

class Solution {
    public int addDigits(int num) {
        return (num - 1) % 9 + 1;
    }
}

268、丢失的数字 

我的答案:

class Solution {
    public int missingNumber(int[] nums) {
        Arrays.sort(nums);
        if(nums[0]==1) return 0;//缺失头部
        for(int i=0;i<nums.length-1;i++){
            if(nums[i+1]-nums[i]>1)
                return nums[i]+1;
        }
        return nums[nums.length-1]+1;//缺失尾部
    }
}

 官方答案:

法一:排序

class Solution {
    public int missingNumber(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            if (nums[i] != i) {
                return i;
            }
        }
        return n;
    }
}

法二:哈希集合

首先遍历数组nums,将数组中的每个元素加入哈希集合,然后依次检查从0 到 n 的每个整数是否在哈希集合中,不在哈希集合中的数字即为丢失的数字。

class Solution {
    public int missingNumber(int[] nums) {
        Set<Integer> set = new HashSet<Integer>();
        int n = nums.length;
        for (int i = 0; i < n; i++) {//将数组中的每个元素加入哈希集合
            set.add(nums[i]);
        }
        int missing = -1;//定义一个新变量,初始化为-1
        for (int i = 0; i <= n; i++) {
            if (!set.contains(i)) {//该数不在哈希集合中,即为丢失的数字
                missing = i;
                break;
            }
        }
        return missing;
    }
}

法三:位运算 

class Solution {
    public int missingNumber(int[] nums) {
        int xor = 0;
        int n = nums.length;
        for (int i = 0; i < n; i++) {//两个相同的数做与运算的结果为0
            xor ^= nums[i];
        }
        for (int i = 0; i <= n; i++) {//相当于在原数组后面增加了0 ~ n的每个整数,只有丢失的数字出现了一次,所以与运算后剩下的就是它
            xor ^= i;
        }
        return xor;
    }
}

法四:数学 

高斯求和公式:

class Solution {
    public int missingNumber(int[] nums) {
        int n = nums.length;
        int total = n * (n + 1) / 2;//正常的和
        int arrSum = 0;
        for (int i = 0; i < n; i++) {//缺了数字的和
            arrSum += nums[i];
        }
        return total - arrSum;
    }
}

290、单词规律

 我的答案:

class Solution {
    public boolean wordPattern(String pattern, String s) {
        String[] arr=s.split(" ");
        if(pattern.length()!=arr.length){
            return false;
        }
        List<Integer> list=new ArrayList<>();//list存储是每个字母出现的所有下标
        List<String> list2=new ArrayList<>();//记录每个字母对应的单词,防止不同的字母对应相同的单词
        for(int i=0;i<26;i++){//26个字母
            for(int j=0;j<pattern.length();j++){
                if(pattern.charAt(j)==(char)('a'+i)){
                    list.add(j);//存储下标
                    if((!arr[j].equals(arr[list.get(0)]))||list2.contains(arr[j])){
                        //两种情况:
                        //一:同一字母却对应了不同的单词
                        //二:不同字母却对应了相同的单词
                        return false;
                    }
                }
                
            }
            if(!list.isEmpty()){
                list2.add(arr[list.get(0)]);//存储当前字母对应的单词
            }
            
            list.clear();//清空存储下标的链表
            
        }
        
        return true;
    }
}

官方答案:

法一:哈希表

任意一个字符都对应着唯一的字符串,任意一个字符串也只被唯一的一个字符对应。在集合论中,这种关系被称为双射。

class Solution {
    public boolean wordPattern(String pattern, String str) {
        Map<String, Character> str2ch = new HashMap<String, Character>();
        Map<Character, String> ch2str = new HashMap<Character, String>();
        int m = str.length();
        int i = 0;
        for (int p = 0; p < pattern.length(); ++p) {//枚举 pattern 中的每一个字符
            char ch = pattern.charAt(p);
            if (i >= m) {
                return false;
            }
            int j = i;
            while (j < m && str.charAt(j) != ' ') {
                j++;
            }
            String tmp = str.substring(i, j);//利用双指针来均摊线性地找到该字符在 str 中对应的字符串
            if (str2ch.containsKey(tmp) && str2ch.get(tmp) != ch) {
                return false;
            }
            if (ch2str.containsKey(ch) && !tmp.equals(ch2str.get(ch))) {
                return false;
            }
            str2ch.put(tmp, ch);//记录每一个字符串对应的字符
            ch2str.put(ch, tmp);//记录每一个字符对应的字符串
            i = j + 1;
        }
        return i >= m;
    }
}

网友答案:

class Solution {
    public boolean wordPattern(String pattern, String str) {
        String[] words = str.split(" ");
        //字符和单词是互相映射,数量必须相等
        if (words.length != pattern.length()) {
            return false;
        }
        Map<Object, Integer> map = new HashMap<>();
        for (Integer i = 0; i < words.length; i++) {
            /*
                如果key不存在,插入成功,返回null;如果key存在,返回之前对应的value。

                以pattern = "abba", str = "dog cat cat dog"为例,
                第1次:map.put('a',0)返回null,map.put("dog",0)返回null,两者相等;
                第2次:map.put('b',1)返回null,map.put("cat",1)返回null,两者相等;
                第3次:map.put('b',2)返回1,map.put("cat",2)返回1,两者相等;
                第4次:map.put('a',3)返回0,map.put("dog",3)返回0,两者相等,
                结果为 true。

                以pattern = "abba", str = "dog cat cat fish"为例,
                第1次:map.put('a',0)返回null,map.put("dog",0)返回null,两者相等;
                第2次:map.put('b',1)返回null,map.put("cat",1)返回null,两者相等;
                第3次:map.put('b',2)返回1,map.put("cat",2)返回1,两者相等;
                第4次:map.put('a',3)返回0,map.put("fish",3)返回null,两者不相等,
                结果为 false。
            */
            if (map.put(pattern.charAt(i), i) != map.put(words[i], i)) {
                return false;
            }
        }
        return true;
    }
}

 326、3的幂

 我的答案:

class Solution {
    public boolean isPowerOfThree(int n) {
        if(n<=0) return false;
        while(n!=1){
            if(n%3!=0){
                return false;
            }
            n=n/3;
            if(n>1&&n<3){
                return false;
            }
        }
        return true;
    }
}

 官方答案:

法一:试除法

class Solution {
    public boolean isPowerOfThree(int n) {//不断地将n 除以3,直到n==1
        while (n != 0 && n % 3 == 0) {
            n /= 3;
        }
        return n == 1;
    }
}

法二:判断是否为最大 3 的幂的约数

在题目给定的32位有符号整数的范围内,最大的3的幂为3^19=1162261467。我们只需要判断n是否是3^19的约数即可。

class Solution {
    public boolean isPowerOfThree(int n) {
        return n > 0 && 1162261467 % n == 0;
    }
}

 338、比特位计数

我的答案:

class Solution {
    public int[] countBits(int n) {
        int[] arr=new int[n+1];
        if(n==0){
            arr[0]=0;
            return arr;
        }
        int counts=0;//计数器,计数每个二进制数中1的个数
        for(int i=0;i<n;i++){
            int j=i+1;
            counts=0;
            while(j!=0){
                if(j%2==1){
                    counts++;
                }
                j=j/2;
            }
            arr[i+1]=counts;
        }
        return arr;
    }
}

 官方答案:

法一:Brian KernighanBrian 算法

Brian Kernighan算法的原理是:对于任意整数x,令x=x &(x-1),该运算将x的二进制表示的最后一个1变成0。因此对x重复该操作,直到x变成0,则操作次数即为x的「一比特数」。

class Solution {
    public int[] countBits(int n) {
        int[] bits = new int[n + 1];
        for (int i = 0; i <= n; i++) {
            bits[i] = countOnes(i);
        }
        return bits;
    }

    public int countOnes(int x) {
        int ones = 0;
        while (x > 0) {
            x &= (x - 1);
            ones++;
        }
        return ones;
    }
}

 法二:动态规划——最高有效位

class Solution {
    public int[] countBits(int n) {
        int[] bits = new int[n + 1];
        int highBit = 0;
        for (int i = 1; i <= n; i++) {
            if ((i & (i - 1)) == 0) {
                highBit = i;
            }
            bits[i] = bits[i - highBit] + 1;
        }
        return bits;
    }
}

法三:动态规划——最低有效位 

class Solution {
    public int[] countBits(int n) {
        int[] bits = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            bits[i] = bits[i >> 1] + (i & 1);
        }
        return bits;
    }
}

法四:动态规划——最低设置位 

class Solution {
    public int[] countBits(int n) {
        int[] bits = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            bits[i] = bits[i & (i - 1)] + 1;
        }
        return bits;
    }
}

342、4的幂

我的答案:

class Solution {
    public boolean isPowerOfFour(int n) {
        if(n<=0) return false;
        while(n!=1){
            if(n%4!=0||(n>1&&n<4)){
                return false;
            }
            n=n/4;
        }
        return true;
    }
}

 

官方答案:

法一:二进制表示中 1 的位置 

如果n是4的幂

  • n也是2的幂 
  • n的二进制表示中有且仅有一个1,这个1后面必须有偶数个0

class Solution {
    public boolean isPowerOfFour(int n) {
        return n > 0 && (n & (n - 1)) == 0 && (n & 0xaaaaaaaa) == 0;
        //n & (n - 1) 用于判断是否是2的幂
        //n & 0xaaaaaaaa 用于判断n二进制表示中的1是否出现在偶数位
        //0xaaaaaaaa 是 二进制的 10101010101010101010101010101010 转成了十六进制,a表示的是十进制的10
    }
}

 法二:取模性质

如果n是4的幂

  • n也是2的幂 
  • n除以3的余数一定是1
class Solution {
    public boolean isPowerOfFour(int n) {
        return n > 0 && (n & (n - 1)) == 0 && n % 3 == 1;
    }
}

344、反转字符串

 我的答案:

class Solution {
    public void reverseString(char[] s) {
        char tmp=' ';
        for(int i=0,j=s.length-1;i<j;i++,j--){
            tmp=s[i];
            s[i]=s[j];
            s[j]=tmp;
        }
        
    }
}

官方答案:

法一:双指针

class Solution {
    public void reverseString(char[] s) {
        int n = s.length;
        for (int left = 0, right = n - 1; left < right; ++left, --right) {
            char tmp = s[left];
            s[left] = s[right];
            s[right] = tmp;
        }
    }
}

349、两个数组的交集

我的答案:

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        List<Integer> list1=new ArrayList<>();
        for(int i=0;i<nums1.length;i++){
            list1.add(nums1[i]);
        }
        List<Integer> list2=new ArrayList<>();
        for(int i=0;i<nums2.length;i++){
            list2.add(nums2[i]);
        }
        List<Integer> list3=new ArrayList<>();
        for(int i=0,j=0;i<list1.size();i++){
            if(list2.contains(list1.get(i))&&(!list3.contains(list1.get(i)))){
                list3.add(list1.get(i));
            }
        }
        int[] same=new int[list3.size()];
        for(int i=0;i<list3.size();i++){
            same[i]=list3.get(i);
        }
        return same;
    }
}
//与官方的方法一思路相同,只是官方用哈希表,我用链表,同样是为了它们的contains()方法

 

法一:两个集合

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        Set<Integer> set1 = new HashSet<Integer>();
        Set<Integer> set2 = new HashSet<Integer>();
        for (int num : nums1) {//把数组1的元素都存入哈希表,方便查找
            set1.add(num);
        }
        for (int num : nums2) {//把数组2的元素都存入哈希表
            set2.add(num);
        }
        return getIntersection(set1, set2);//封装成函数体
    }

    public int[] getIntersection(Set<Integer> set1, Set<Integer> set2) {
        if (set1.size() > set2.size()) {
            return getIntersection(set2, set1);
        }
        Set<Integer> intersectionSet = new HashSet<Integer>();//该哈希用于存储交集
        for (int num : set1) {//遍历较小的集合,判断其中的每个元素是否在另一个集合中
            if (set2.contains(num)) {
                intersectionSet.add(num);
            }
        }
        int[] intersection = new int[intersectionSet.size()];
        int index = 0;
        for (int num : intersectionSet) {//把哈希表的元素再转存到数组中返回
            intersection[index++] = num;
        }
        return intersection;
    }
}

法二:排序 + 双指针 

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        int length1 = nums1.length, length2 = nums2.length;
        int[] intersection = new int[length1 + length2];//存储交集的数组
        int index = 0, index1 = 0, index2 = 0;
        while (index1 < length1 && index2 < length2) {
            int num1 = nums1[index1], num2 = nums2[index2];
            if (num1 == num2) {
                // 保证加入元素的唯一性
                if (index == 0 || num1 != intersection[index - 1]) {//相同的元素一定排列在一起,所以加入前先看看它前面那个是否和它相等
                    intersection[index++] = num1;
                }
                index1++;
                index2++;
            } else if (num1 < num2) {
                index1++;//指针右移
            } else {
                index2++;
            }
        }
        return Arrays.copyOfRange(intersection, 0, index);
    }
}

 367、有效的完全平方数

我的答案:

class Solution {
    public boolean isPerfectSquare(int num) {
        for(int i=1;i<num;i++){
            if(i*i<num&&(i+1)*(i+1)>num){
                return false;
            }else if(i*i==num){
                return true;
            }
        }
        return num==1?true:false;
    }
}

官方答案:

法一:使用内置的开方库函数

class Solution {
    public boolean isPerfectSquare(int num) {
        int x = (int) Math.sqrt(num);
        return x * x == num;
    }
}

 法二:暴力

class Solution {
    public boolean isPerfectSquare(int num) {
        long x = 1, square = 1;
        while (square <= num) {//从1开始查找,看每个数的平方是否等于num,如果大于num就不用找了
            if (square == num) {
                return true;
            }
            ++x;
            square = x * x;
        }
        return false;
    }
}

法三:二分查找

class Solution {
    public boolean isPerfectSquare(int num) {
        int left = 0, right = num;
        while (left <= right) {
            int mid = (right - left) / 2 + left;
            long square = (long) mid * mid;
            if (square < num) {
                left = mid + 1;
            } else if (square > num) {
                right = mid - 1;
            } else {
                return true;
            }
        }
        return false;
    }
}

 法四:牛顿迭代法 

class Solution {
    public boolean isPerfectSquare(int num) {
        double x0 = num;
        while (true) {
            double x1 = (x0 + num / x0) / 2;
            if (x0 - x1 < 1e-6) {
                break;
            }
            x0 = x1;
        }
        int x = (int) x0;
        return x * x == num;
    }
}

387、字符串的第一个唯一字符

我的答案:

class Solution {
    public int firstUniqChar(String s) {
        List<Character> list=new ArrayList<>();
        char tmp='1';
        for(int i=0;i<s.length();i++){//把字符串里的字符都存入链表中
            list.add(s.charAt(i));
        }
        if(s.length()==1) return 0;
        for(int i=0;i<s.length();i++){
            if(list.indexOf(list.get(i))==list.lastIndexOf(list.get(i))){//判断该元素第一次出现的下标和最后一次出现的下标是否相同
                return i;
            }
        }
        return -1;
    }
}

 

官方答案: 

法一:使用哈希表存储频数

class Solution {
    public int firstUniqChar(String s) {
        Map<Character, Integer> frequency = new HashMap<Character, Integer>();
        for (int i = 0; i < s.length(); ++i) {
            char ch = s.charAt(i);
            frequency.put(ch, frequency.getOrDefault(ch, 0) + 1);//键为字符,值为字符出现的次数
        }
        for (int i = 0; i < s.length(); ++i) {
            if (frequency.get(s.charAt(i)) == 1) {//查找出现次数为1的字符
                return i;
            }
        }
        return -1;
    }
}

法二:使用哈希表存储索引 

class Solution {
    public int firstUniqChar(String s) {
        Map<Character, Integer> position = new HashMap<Character, Integer>();
        int n = s.length();
        for (int i = 0; i < n; ++i) {//统计每个字符出现的次数
            char ch = s.charAt(i);
            if (position.containsKey(ch)) {//字符多次出现,索引值赋为-1
                position.put(ch, -1);
            } else {
                position.put(ch, i);
            }
        }
        int first = n;
        for (Map.Entry<Character, Integer> entry : position.entrySet()) {//遍历哈希表
            int pos = entry.getValue();
            if (pos != -1 && pos < first) {//找出其中不为−1 的最小索引值
                first = pos;
            }
        }
        if (first == n) {
            first = -1;
        }
        return first;
    }
}

法三:队列 

class Solution {
    public int firstUniqChar(String s) {
        Map<Character, Integer> position = new HashMap<Character, Integer>();
        Queue<Pair> queue = new LinkedList<Pair>();
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            char ch = s.charAt(i);
            if (!position.containsKey(ch)) {//若当前遍历到的字符不在哈希表中,就把它加入哈希表和队列
                position.put(ch, i);
                queue.offer(new Pair(ch, i));
            } else {
                position.put(ch, -1);
                while (!queue.isEmpty() && position.get(queue.peek().ch) == -1) {
                //不断地根据哈希映射中存储的值(是否为−1)选择弹出队首的元素,直到队首元素「真的」只出现了一次或者队列为空
                    queue.poll();
                }
            }
        }
        return queue.isEmpty() ? -1 : queue.poll().pos;
    }

    class Pair {//定义一个Pair类,为了使队列能够存储键值对这样的数据
        char ch;
        int pos;

        Pair(char ch, int pos) {
            this.ch = ch;
            this.pos = pos;
        }
    }
}

网友答案:

class Solution {
    public int firstUniqChar(String s) {
        char[] cs = s.toCharArray();
        char[] chars = new char[128];//字符的ASCII码有127个
        for(int i = 0 ; i < cs.length; i++){//以字符的ASCII码为下标,字符出现的次数为数组的元素
            chars[cs[i]]++;
        }
        for(int i = 0; i < cs.length; i++){
            if(chars[cs[i]] == 1){
                return i;
            }
        }
        return -1;
    }
}

389、找不同

我的答案:

class Solution {
    public char findTheDifference(String s, String t) {
        if(s.length()==0){
            return t.charAt(0);
        }
        char[] c1=new char[s.length()];
        for(int i=0;i<s.length();i++){
            c1[i]=s.charAt(i);
        }
        char[] c2=new char[t.length()];
        for(int i=0;i<t.length();i++){
            c2[i]=t.charAt(i);
        }
        Arrays.sort(c1);
        Arrays.sort(c2);
        for(int i=0;i<s.length();i++){
            if(c1[i]!=c2[i]){
                return  c2[i];
            }
        }
        return c2[t.length()-1];
    }
}

官方答案: 

法一:计数

class Solution {
    public char findTheDifference(String s, String t) {
        int[] cnt = new int[26];
        for (int i = 0; i < s.length(); ++i) {//统计字符串s中字符出现的次数
            char ch = s.charAt(i);
            cnt[ch - 'a']++;
        }
        for (int i = 0; i < t.length(); ++i) {//减去字符串t中字符出现的次数,如果出现负数,即为所求
            char ch = t.charAt(i);
            cnt[ch - 'a']--;
            if (cnt[ch - 'a'] < 0) {
                return ch;
            }
        }
        return ' ';
    }
}

法二:求和 

class Solution {
    public char findTheDifference(String s, String t) {
        int as = 0, at = 0;
        for (int i = 0; i < s.length(); ++i) {//将字符串s 中每个字符的 ASCII 码的值求和
            as += s.charAt(i);
        }
        for (int i = 0; i < t.length(); ++i) {//将字符串t 中每个字符的 ASCII 码的值求和
            at += t.charAt(i);
        }
        return (char) (at - as);//两个和的差值即为所求字符的ASCII码值
    }
}

 法三:位运算

将两个字符串拼接成一个字符串,将问题转换成求字符串中出现奇数次的字符

class Solution {
    public char findTheDifference(String s, String t) {
        int ret = 0;
        for (int i = 0; i < s.length(); ++i) {
            ret ^= s.charAt(i);
        }
        for (int i = 0; i < t.length(); ++i) {
            ret ^= t.charAt(i);
        }
        return (char) ret;
    }
}

 392、判断子序列

 

我的答案:

class Solution {
    public boolean isSubsequence(String s, String t) {
        if(t.length()<s.length()){//子串必定小于等于母串长度
            return false;
        }
        
        for(int i=0,j=0;i<s.length();i++){
            
            for(;j<t.length();j++){
                if(s.charAt(i)==t.charAt(j)){//如果相同,直接跳出内层循环,比较下一个字符
                    j++;
                    break;
                }
                if(i==s.length()-1&&j==t.length()-1){//s串的最后一个字符不正确
                    if(s.charAt(i)!=t.charAt(j)){
                        return false;
                    }
                }
            }
            if((s.length()==1||i<(s.length()-1))&&j>t.length()-1){//s串的第一个或者中间的某个字符不正确
                return false;
            }
            
        }
        
        return true;
    }
}
/**
1、仅有子串或母串长度为0
2、子串的顺序错乱
3、子串只有前面一小部分是t的子序列 */

 官方答案:

法一:双指针

class Solution {
    public boolean isSubsequence(String s, String t) {
        int n = s.length(), m = t.length();
        int i = 0, j = 0;
        while (i < n && j < m) {
            if (s.charAt(i) == t.charAt(j)) {
                i++;
            }
            j++;
        }
        return i == n;
    }
}

法二:动态规划 

class Solution {
    public boolean isSubsequence(String s, String t) {
        int n = s.length(), m = t.length();

        int[][] f = new int[m + 1][26];
        for (int i = 0; i < 26; i++) {
            f[m][i] = m;
        }

        for (int i = m - 1; i >= 0; i--) {
            for (int j = 0; j < 26; j++) {
                if (t.charAt(i) == j + 'a')
                    f[i][j] = i;
                else
                    f[i][j] = f[i + 1][j];
            }
        }
        int add = 0;
        for (int i = 0; i < n; i++) {
            if (f[add][s.charAt(i) - 'a'] == m) {
                return false;
            }
            add = f[add][s.charAt(i) - 'a'] + 1;
        }
        return true;
    }
}

409、最长回文串

 我的答案: 

class Solution {
    public int longestPalindrome(String s) {
        if(s.length()==1){
            return 1;
        }

        int[] counts=new int[s.length()];
        char[] tmp=s.toCharArray();
        Arrays.sort(tmp);
        int i=0,j=0;//用于各种遍历的指针
        int count=0;
        int len=0;//回文串的长度

        
        //统计字符的个数
        for(i=0;i<s.length();){
            for(j=i+1;j<s.length();j++){
                if(tmp[i]!=tmp[j]){//字符数组已经排过序,相同的字符必定是靠在一起的
                    counts[count++]=j-i;//该字符的个数
                    break;
                }
            }
            if(j==s.length()){
                counts[count++]=j-i;
                break;
            }
            i=j;
        }
        boolean flag=true;
        for(i=0;i<count;i++){
            if(counts[i]%2==0){//数量为偶数的字符,全部留下
                len+=counts[i];
            }else if(counts[i]%2==1){
                if(flag){//数量为奇数的字符可以派一个去中间位置站
                    len+=counts[i];
                    flag=false;
                }else{//中间的位置已经没有了,其他数量为奇数的字符只能留下偶数个字符用于构造回文串
                    len+=counts[i]-1;     
                }          
            }
        }
        return len;
    }
}

官方答案:

法一:贪心

在一个回文串中,只有最多一个字符出现了奇数次,其余的字符都出现偶数次,只有一个出现次数为奇数的字符可以加入回文串

class Solution {
    public int longestPalindrome(String s) {
        int[] count = new int[128];
        int length = s.length();
        for (int i = 0; i < length; ++i) {//统计字符出现的次数
            char c = s.charAt(i);
            count[c]++;
        }

        int ans = 0;
        for (int v: count) {
            ans += v / 2 * 2;//v是字符出现的次数,v/2是回文串左边放一半,右边放一半,所以该字符在回文串里总共是v/2*2个
            if (v % 2 == 1 && ans % 2 == 0) {//v第一次出现奇数时,ans+1,也变成奇数,此后就不会再进入if判断了
                ans++;
            }
        }
        return ans;
    }
}

 网友答案:

public int longestPalindrome(String s) {
        char[] occurs = new char[128];

        int ans = 0;
        for (int i = 0; i < s.length(); ++i) {
            char c = s.charAt(i);
            occurs[c]++;
            if (occurs[c] == 2) {//遇到偶数就加上
                ans += 2;
                occurs[c] = 0;
            }
        }

        if (ans < s.length()) ans++;//如果字符全部出现了偶数次,那最后ans一定等于s.length(),否则,就有字符出现了奇数次,ans+1
        return ans;
    }

412、Fizz Buzz

 我的答案:

class Solution {
    public List<String> fizzBuzz(int n) {
        List<String> list=new ArrayList<>();
        for(int i=1;i<=n;i++){
            if(i%3==0&&i%5==0){
                list.add("FizzBuzz");
            }else if(i%3==0){
                list.add("Fizz");
            }else if(i%5==0){
                list.add("Buzz");
            }else{
                list.add(String.valueOf(i));//把整数转成字符串
            }
        }
        return list;
    }
}

 

官方答案:

法一:模拟 + 字符串拼接

class Solution {
    public List<String> fizzBuzz(int n) {
        List<String> answer = new ArrayList<String>();
        for (int i = 1; i <= n; i++) {
            StringBuffer sb = new StringBuffer();//StringBuffer有拼接的方法append()
            if (i % 3 == 0) {
                sb.append("Fizz");
            }
            if (i % 5 == 0) {
                sb.append("Buzz");
            }
            if (sb.length() == 0) {
                sb.append(i);
            }
            answer.add(sb.toString());//toString()把StringBuffer类型的sb转成String类型
        }
        return answer;
    }
}

414、第三大的数

 我的答案:

class Solution {
    public int thirdMax(int[] nums) {
        Arrays.sort(nums);//升序排序
        int len=nums.length;
        if(nums.length<3){
            return nums[len-1];
        }
        int count=1;//计数器
        for(int i=len-2;i>=0;i--){
            if(nums[i]!=nums[i+1]){
                count++;
                if(count==3){
                    return nums[i];
                }
            }
        }
        return nums[len-1];//count<3且nums.length>=3的情况
    }
}

官方答案:

 法一:排序

class Solution {
    public int thirdMax(int[] nums) {
        Arrays.sort(nums);//升序
        reverse(nums);//反转后变成降序
        for (int i = 1, diff = 1; i < nums.length; ++i) {//通过判断相邻元素是否不同,来统计不同元素的个数
            if (nums[i] != nums[i - 1] && ++diff == 3) { // 此时 nums[i] 就是第三大的数
                return nums[i];
            }
        }
        return nums[0];
    }

    public void reverse(int[] nums) {
        int left = 0, right = nums.length - 1;
        while (left < right) {
            int temp = nums[left];
            nums[left] = nums[right];
            nums[right] = temp;
            left++;
            right--;
        }
    }
}

法二:有序集合 

用一个有序集合来维护数组中前三大的数

class Solution {
    public int thirdMax(int[] nums) {
        TreeSet<Integer> s = new TreeSet<Integer>();//用一个有序集合来维护数组中前三大的数,小根堆
        for (int num : nums) {
            s.add(num);
            if (s.size() > 3) {
                s.remove(s.first());//删除集合中最小的元素
            }
        }
        return s.size() == 3 ? s.first() : s.last();//不足3就返回最末位的最大值
    }
}

法三:一次遍历 

用三个变量 a、b 和 c 来维护数组中的最大值、次大值和第三大值

class Solution {
    public int thirdMax(int[] nums) {
        long a = Long.MIN_VALUE, b = Long.MIN_VALUE, c = Long.MIN_VALUE;
        for (long num : nums) {
            if (num > a) {
                c = b;
                b = a;
                a = num;
            } else if (a > num && num > b) {
                c = b;
                b = num;
            } else if (b > num && num > c) {
                c = num;
            }
        }
        return c == Long.MIN_VALUE ? (int) a : (int) c;
    }
}
class Solution {
    public int thirdMax(int[] nums) {
        Integer a = null, b = null, c = null;//无穷小
        for (int num : nums) {
            if (a == null || num > a) {
                c = b;
                b = a;
                a = num;
            } else if (a > num && (b == null || num > b)) {
                c = b;
                b = num;
            } else if (b != null && b > num && (c == null || num > c)) {
                c = num;
            }
        }
        return c == null ? a : c;
    }
}

 434、字符串中的单词数

 我的答案:

class Solution {
    public int countSegments(String s) {
        s=s.trim();
        if(s.length()==0) return 0;
        return s.split("\s+").length;//\s+表示1个或多个空格
    }
}

官方答案:

法一:原地法

遍历整个字符串,统计每个单词的第一个下标的数目:

  • 该下标对应的字符不为空格;
  • 该下标为初始下标或者该下标的前下标对应的字符为空格;
class Solution {
    public int countSegments(String s) {
        int segmentCount = 0;

        for (int i = 0; i < s.length(); i++) {
            if ((i == 0 || s.charAt(i - 1) == ' ') && s.charAt(i) != ' ') {//该下标为初始下标或者该下标的前下标对应的字符为空格;该下标对应的字符不为空格
                segmentCount++;
            }
        }

        return segmentCount;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/501616.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Github 使用教学

&#x1f4ad; 写在前面&#xff1a;本章我们将介绍 Git 的基本使用方法&#xff0c;包括注册 GitHub 账号、设置 Git、创建本地存储库、复制本地存储库、导入远程存储库、追加、提交、合并等常用操作。我们还会教你如何在 GitHub 上创建项目&#xff0c;使用 git clone 命令克…

盘“底座”,盘出新生意经

本文转自首席信息官 作者 徐蕊 导读 卖“底座”&#xff0c;这是一门新的生意&#xff0c;也是用友与友商差异化的商业竞争优势所在。 大型企业都在建“数智化底座” 有这样两类企业&#xff0c;他们截然不同&#xff0c;但在数智化的建设上殊途同归。 随着中国经济的发展&a…

SLAM论文速递:经典动态SLAM解析—(2021)DP-SLAM:面向动态环境的移动概率视觉SLAM—5.08(1)

论文信息 题目&#xff1a; DP-SLAM:A visual SLAM with moving probability towards dynamic environments DP-SLAM:面向动态环境的移动概率视觉SLAM论文地址&#xff1a; 发表期刊&#xff1a; 标签 语义分割几何约束、动态概率传播、 摘要 文中提出了一种基于稀疏特征的视觉…

DDD分层架构浅析

大家好&#xff0c;我是易安&#xff01;今天我们聊下DDD分层架构 微服务架构模型有好多种&#xff0c;例如整洁架构、CQRS和六边形架构等等。每种架构模式虽然提出的时代和背景不同&#xff0c;但其核心理念都是为了设计出“高内聚低耦合”的架构&#xff0c;轻松实现架构演进…

【P12】JMeter 准确的吞吐量定时器(Precise Throughput Timer)

&#xff08;1&#xff09;、测试计划右键 <<< 添加 <<< 定时器 <<< 准确的吞吐量定时器&#xff08;Precise Throughput Timer&#xff09; 目标吞吐量&#xff08;每个“吞吐期”的样本&#xff09;&#xff1a;15.0 吞吐量周期&#xff08;秒&a…

ArcGIS植被覆盖度计算与栅格计算

遥感&#xff0c;顾名思义就是遥远的感知。就是利用飞机、卫星等平台对地球进行观测并获取数据。这里的数据可以使光谱数据、磁场数据等。今天我们就用一个简单的例子来说明ArcGIS对遥感数据的处理&#xff0c;但是ArcGIS处理遥感并没有其他专业遥感软件如ENVI那样强大&#xf…

(转载)04.Matplotlib-文本注释数学表达式设置

1. matplotlib.pyplot.text 文本基本参数设置 2. matplotlib.pyplot.annotate 注释基本参数设置 Matplotlib 支持绘制 TeX 包含的数学符号。TeX 是一套功能强大、十分灵活的排版语言&#xff0c;它可以用来绘制文本、符号、数学表达式等。通过下表中的方法可以绘制出相应的内容…

Java基础学习(13)

Java基础学习 一、File1.1 File详情1.2 File常见的成员方法1.2.1 判断获取1.2.2 创建删除1.2.3 获取遍历 二、IO流2.1 IO流体系2.2 FileOutputStream2.2.1 FileOutputStream写数据的3种方式2.2.2 FileOutputStream换行写:2.2.3 FileOutputStream续写 2.3 FilelnputStream拷贝文…

Go语言中的流程控制语句

目录 流程控制语句 if语句 ifelse语句 switch语句 for循环 break语句 continue语句 goto语句 流程控制语句 if语句 在Go语言中&#xff0c;可以在if后面加上一段执行语句&#xff0c;执行语句也可以用作对if条件的判断。它的语法格式为&#xff1a; if a : conditio…

MySQL_3 数据库的“CRUD“

目录 一、添加数据 1.基本语法 : 2.代码演示 : 二、查找数据 1.基本语法 : 2.代码演示 : 3.查询中的计算 : 4.WHERE子句的扩展 : 5.排序查询 : 三、修改数据 1.基本语法 : 2.代码演示 : 四、删除数据 1.基本语法 : 2.代码演示 : 一、添加数据 1.基本语法 : INS…

吹爆,全网第一个手把手教你从零开始搭建Spring Cloud Alibaba的笔记

Spring Cloud Alibaba 是阿里巴巴提供的微服务开发一站式解决方案&#xff0c;是阿里巴巴开源中间件与 Spring Cloud 体系的融合。 Springcloud 和 Srpingcloud Alibaba 区别&#xff1f; SpringCloud&#xff1a; 部分组件停止维护和更新&#xff0c;给开发带来不便;SpringCl…

stm32103ZET6使用编码器(磁电增量式)

这里写目录标题 磁电增量式编码器介绍TIM定时器&#xff08;编码器接口模式&#xff09;一些用到的算法均值滤波冒泡排序&#xff08;从小到大&#xff09;一阶低通滤波 编码器测数代码编码器接口HAL库函数 正点原子的电机例程(原例程用的是stm32f407&#xff0c;我这里改成用s…

ClickHouse:对不同类型Join的支持

ClickHouse 是一个流行的开源实时分析数据库&#xff0c;旨在为需要在大量数据上进行超低延迟分析查询的用例提供最佳性能。为了在分析应用程序中实现最佳性能&#xff0c;通常需要将表组合在一起进行数据非规范化处理。扁平化表通过避免联接来帮助最小化查询延迟&#xff0c;以…

从零开始学【网络安全】

前言&#xff1a;网络安全如何从零开始学习&#xff0c;少走弯路&#xff1f; 目录&#xff1a; 一&#xff0c;怎么入门&#xff1f; 1、Web 安全相关概念&#xff08;2 周&#xff09;2、熟悉渗透相关工具&#xff08;3 周&#xff09;3、渗透实战操作&#xff08;5 周&…

DevData Talks | 思码逸陆春蕊:研发效能度量落地的难点与计策

本期 DevData Talks 直播活动邀请到的重磅嘉宾是思码逸高级咨询专家陆春蕊老师。陆春蕊老师曾就职于Oracle&#xff0c;在软件质量、项目管理方面有着丰富的经验&#xff0c;在思码逸为上百家客户提供了研发效能体系、数据分析、实践落地等方面的咨询。 陆春蕊老师与我们聊了聊…

QML绘图便捷接口类Convenient API

在绘制矩形时&#xff0c;我们提供了一个便捷的接口&#xff0c;而不需要调用stroke或者fill来完成。 3.import QtQuick 2.0 4. 5.Canvas { 6. id: root 7. width: 120; height: 120 8. onPaint: { 9. var ctx getContext("2d") 10. ctx.fi…

了解进程控制

目录 1、基本概念 2、操作系统内核 2.1支撑功能 2.2资源管理功能 3、进程的创建 3.1进程的层次结构 3.2进程图 3.3引起创建进程的事件 3.4进程的创建 4、进程的终止 4.1引起进程终止的事件 4.2进程的终止过程 5、进程阻塞与唤醒 5.1引起进程阻塞和唤醒的事件 5.2进…

老测试告诉你自动化测试需要考虑什么?

写在前面 这篇文章译自著名测试专家James Bach的《Test Automation Snake Oil》一文&#xff0c;是笔者在学习和研究探索性测试时偶然发现的一篇较有意义的文章&#xff0c;很好地解答了我们对自动化测试的疑惑。 比如万能的自动化测试是否可以替代一切&#xff0c;还给我们提…

什么是多相流?在熟悉工业中常见的两相及多相流的分类及特点

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…

安全工程与运营

安全工程与运营 系统安全工程系统安全工程重要性安全工程系统安全工程理论基础 成立成熟度模型、系统安全工程能力成熟度模型能力成熟度模型&#xff08;Capability Maturity Model&#xff09;能力成熟度模型基本思想系统安全工程能力成熟度模型SSE-CMM的作用SSE-CMM体系结构域…