力扣算法必刷题(周更)

数据结构与算法

LeetCode必刷

1. 两数之和(leetcode-1)

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]
class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] indexs=new int[2]; //定义返回数组
        Map map=new HashMap<>(); //定义map用于存储值数组里的值与它的index
        for (int i = 0; i < nums.length; i++) { //对数组进行遍历
            int needNum=target-nums[i]; //需要的值:比如目标值为9,index=0的值为2,needNum则为7
            if (map.containsKey(needNum)){ //判断需要的值是否在map中
                indexs[0]=map.get(needNum);//从map中取出needNum的下标
                indexs[1]=i; //存储此时的index
                return indexs;
            }
            map.put(nums[i],i); //把数组中值进行存储到map中
        }
        return indexs;
    }
}

2. 回文数(leetcode-9)

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

  • 例如,121 是回文,而 123 不是。

示例 1:

输入:x = 121
输出:true

示例 2:

输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
class Solution {
    public boolean isPalindrome(int x) {
        String str = String.valueOf(x);
        String reverseStr = new StringBuilder(str).reverse().toString();
        if (str.equals(reverseStr)){
            return true;
        }else return false;
    }
}

3. 整数反转(leetcode-7)

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

示例 1:

输入:x = 123
输出:321

示例 2:

输入:x = -123
输出:-321
class Solution {
    public int reverse(int x) {
        int result=0;
        while (x!=0){
            //最小位的数
            int lowBit=x%10;
            //去掉最低位后的数 例:1234->123
            x=x/10;
            // int范围:        -2147483648——2147483647
            /**
             * 反转时可能会超过int最大值,发生溢出
             * result*10+lowBit>Integer.MAX
             * result>=Integer.MAX/10   可能溢出
             *     (1) result>MAX  一定溢出
             *     (2) result=MAX  && lowBit>7 一定溢出
             *     
             *负数同理
             */

            if (result > Integer.MAX_VALUE/10 || (result == Integer.MAX_VALUE/10 && lowBit > 7))
                return 0;
            if (result < Integer.MIN_VALUE/10 || (result == Integer.MIN_VALUE/10 && lowBit < -8))
                return 0;
            result=result*10+lowBit; //例子:123-->3-->3*10+2-->(3*10+2)*10+1=321
        }
        return result;
    }
}

4. 二进制求和

给你两个二进制字符串,返回它们的和(用二进制表示)。

输入为 非空 字符串且只包含数字 10

示例 1:

输入: a = "11", b = "1"
输出: "100"

示例 2:

输入: a = "1010", b = "1011"
输出: "10101"
class Solution {
    public String addBinary(String a, String b) {
        /**
         *    jinwei:0 0 0 1
         *         a:0 0 1 1
         *         b:0 1 1 1
         *           0 1 2 3
         */
        int alen = a.length();
        int blen = b.length();

        int jinwei = 0;
        String result = "";
        while (alen > 0 || blen > 0) {
            int sum = 0;
            sum += jinwei;
            if (alen > 0) {
                String aLastStr = a.substring(alen - 1, alen);
                int aLastInt = Integer.parseInt(aLastStr);
                sum += aLastInt;
                alen--;
            }
            if (blen > 0) {
                String bLastStr = b.substring(blen - 1, blen);
                int bLastInt = Integer.parseInt(bLastStr);
                sum += bLastInt;
                blen--;
            }
            switch (sum) {
                case 2:
                    jinwei = 1;
                    result = "0" + result;
                    break;
                case 3:
                    jinwei = 1;
                    result = "1" + result;
                    break;
                default:
                    jinwei = 0;
                    result = sum + "" + result;
            }
        }
        if (jinwei == 1) {
            result = "1" + result;
        }
        return result;
    }
}

5. 罗马数字转整数

罗马数字包含以下七种字符: IVXLCDM

字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II27 写做 XXVII, 即为 XX + V + II

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

  • I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
  • X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
  • C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

给定一个罗马数字,将其转换成整数。

示例 1:

输入: s = "III"
输出: 3

示例 2:

输入: s = "IV"
输出: 4
class Solution {
    public int romanToInt(String s) {
        int sum = 0;
        int preValue = getValue(s.charAt(0));
        for (int i = 1; i < s.length(); i++) {
            int value = getValue(s.charAt(i));
            if (preValue < value) {
                sum -= preValue;
            } else {
                sum += preValue;
            }
            preValue = value;
        }
        sum += preValue;
        return sum;
    }

    private int getValue(char ch) {
        switch (ch) {
            case 'I':
                return 1;
            case 'V':
                return 5;
            case 'X':
                return 10;
            case 'L':
                return 50;
            case 'C':
                return 100;
            case 'D':
                return 500;
            case 'M':
                return 1000;
            default:
                return 0;
        }
    }
}

6. x的平方根(leetcode-69)

给你一个非负整数 x ,计算并返回 x算术平方根

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5

示例 1:

输入:x = 4
输出:2
class Solution {
/**
 *      二分查找
 *    例子: x=10
 *     left:1    mid:(1+10+1)/2=6   right:10
 *                   36>10
 *     left:1    mid:(1+5+1)/2=3   right:5
 *                   9<=10
 *     left:3    mid:(3+5+1)/2=4   right:5
 *                   16>10
 *     left:3    mid:3   right:3    跳出循环,返回 3
 *
 */
    public int mySqrt(int x) {
        int left = 1;
        int right = x;
        while (left < right) {
            /*
             注意(left+right)/2,(left+right+1)/2,
             当left+right为偶数时,在int的取整下,+1实际上是对整数+1/2,对结果无影响,
             而当left+right为奇数时,比如1+10=11 中间值为5.5,取整为5,则精度丢失0.5,+1为6.5,取整为6,就不丢失了
             mid = left + (right - left) / 2 和 mid = (left + right) / 2,相比后者也存在溢出
             */
            int mid = (left+right+1) / 2;
            //mid*mid<=x
            if (mid <= x / mid) {
                left = mid;
            } else {
                right = mid - 1;
            }
        }
        return right;
    }
}

7. 赎金信(leetcode-383)

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

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

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

示例 1:

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

示例 2:

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

示例 3:

输入:ransomNote = "aa", magazine = "aab"
输出:true
class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int[] arr = new int[26];
        int temp;
        for (int i = 0; i < magazine.length(); i++) {
            //ASCII码中a为97
            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;
    }
}

8. 唯一摩尔斯密码词(leetcode-804)

为了方便,所有 26 个英文字母的摩尔斯密码表如下:

[".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."]

给你一个字符串数组 words ,每个单词可以写成每个字母对应摩尔斯密码的组合。

  • 例如,"cab" 可以写成 "-.-..--..." ,(即 "-.-." + ".-" + "-..." 字符串的结合)。我们将这样一个连接过程称作 单词翻译

words 中所有单词进行单词翻译,返回不同 单词翻译 的数量。

示例 1:

输入: words = ["gin", "zen", "gig", "msg"]
输出: 2
解释: 
各单词翻译如下:
"gin" -> "--...-."
"zen" -> "--...-."
"gig" -> "--...--."
"msg" -> "--...--."

共有 2 种不同翻译, "--...-." 和 "--...--.".

示例 2:

输入:words = ["a"]
输出:1
class Solution {
    public int uniqueMorseRepresentations(String[] words) {
        String[] table = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."};
        Set set = new HashSet<>();
        for (String word : words) {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < word.length(); i++) {
                int index = (int) (word.charAt(i) - 'a');
                stringBuilder.append(table[index]);
            }
            set.add(stringBuilder.toString());
        }
        System.out.println(set);
        return set.size();
    }
}

9. 丢失的数字(leetcode-268)

给定一个包含 [0, n]n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

示例 1:

输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。

示例 2:

输入:nums = [0,1]
输出:2
解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,因为它没有出现在 nums 中。

示例 3:

输入:nums = [9,6,4,2,3,5,7,0,1]
输出:8
解释:n = 9,因为有 9 个数字,所以所有的数字都在范围 [0,9] 内。8 是丢失的数字,因为它没有出现在 nums 中。

示例 4:

输入:nums = [0]
输出:1
解释:n = 1,因为有 1 个数字,所以所有的数字都在范围 [0,1] 内。1 是丢失的数字,因为它没有出现在 nums 中。
class Solution {
    public int maxProfit(int[] prices) {
        int minPrice=Integer.MAX_VALUE;
        int maxProfit=0;
        for (int i = 0; i < prices.length; i++) {
            if (prices[i]maxProfit){
                    maxProfit=profit;
                }
            }
        }
        return maxProfit;
    }
}

10. 斐波那契数列(leetcode-509)

斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 01 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1

给定 n ,请计算 F(n)

示例 1:

输入:n = 2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1
class Solution {
  //方法一
    public int fib(int n) {
        if (n <= 1) {
            return n;
        }
        int a = 0, b = 1, c = 0;
        for (int i = 2; i <= n; i++) {
            c = a + b;
            a = b;
            b = c;
        }
        return c;
    }
  //方法二
  public int fib(int n) {
        int[] fib = new int[n + 2];
        fib[0] = 0;  // 第 0 个斐波那契数
        fib[1] = 1; // 第 1 个斐波那契
        for(int i = 2; i <= n; i++) {
            fib[i] = fib[i-1] + fib[i-2];
        }
        return fib[n];
    }
}

11. 字符串的排列(leetcode-567) ⭐️

给你两个字符串 s1s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false

换句话说,s1 的排列之一是 s2子串

示例 1:

输入:s1 = "ab" s2 = "eidbaooo"
输出:true
解释:s2 包含 s1 的排列之一 ("ba").

示例 2:

输入:s1= "ab" s2 = "eidboaoo"
输出:false
//双指针,滑动窗口算法

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int len1 = s1.length(), len2 = s2.length();
        //s1长度大于s2时,s2必定不会包含s1,直接返回false
        if (len1 > len2) {
            return false;
        }
        //创建字典
        int[] arr1 = new int[26], arr2 = new int[26];
        //以s1的长度为基准,对应字典加1
        for (int i = 0; i < len1; i++) {
            arr1[s1.charAt(i) - 'a']++;
            arr2[s2.charAt(i) - 'a']++;
        }
        //滑动窗口,定义左右边界
        int left = 0, right = len1 - 1;
        //循环条件右边界小于s2长度
        while (right < len2) {
            //如果刚开始s2的前三个字母与s1相等直接返回true
            if (Arrays.equals(arr1, arr2)) return true;
            //右边界右移动
            right++;
            //移动后的右边界不能等于s2的长度,否则就数组越界了
            if (right != len2) {
                //右边界右移一位后当前字母存入字典
                arr2[s2.charAt(right) - 'a']++;
            }
            //同时左边界当前字母要从字典中删除,删除后也同样右移,实现第一次滑动窗口,以此循环,直到两字典相同
            arr2[s2.charAt(left) - 'a']--;
            left++;
        }
        //循环结束,则返回false
        return false;
    }
}

12. 快乐数(leetcode-202)

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n快乐数 就返回 true ;不是,则返回 false

示例 1:

输入:n = 19
输出:true
/**
     *两种情况:1.死循环 2.为1
     * 把每次平方和存入set,有重复元素则返回false,说明进入死循环始终不会为1
     */
class Solution {
    public boolean isHappy(int n) {
        HashSet set = new HashSet<>();
        while (n != 1) {
            n = sum(n);
            if (!set.add(n)) return false;
        }
        return true;

    }
    public int sum(int n) {
        int sum = 0;
        while (n != 0) {
            sum += (n % 10) * (n % 10);
            n = n / 10;
        }
        return sum;
    }
}

14. 丑数(leetcode-263)

丑数 就是只包含质因数 235 的正整数。

给你一个整数 n ,请你判断 n 是否为 丑数 。如果是,返回 true ;否则,返回 false

示例 1:

输入:n = 6
输出:true
解释:6 = 2 × 3
//对 n 反复除以 2,3,5,直到 n 不再包含质因数 2,3,5。若剩下的数等于 1,则说明 n 不包含其他质因数,是丑数;否则,说明 n 包含其他质因数,不是丑数。
class Solution {
    public boolean isUgly(int n) {
        if (n < 0) {
            return false;
        }
        if (n <= 0) {
            return false;
        }
        int[] factors = {2, 3, 5};
        for (int factor : factors) {
            while (n % factor == 0) {
                n /= factor;
            }
        }
        return n == 1;
    }
}

15. 快乐数(leetcode-507)

对于一个 正整数,如果它和除了它自身以外的所有 正因子 之和相等,我们称它为 「完美数」

给定一个 整数 n, 如果是完美数,返回 true;否则返回 false

示例 1:

输入:num = 28
输出:true
解释:28 = 1 + 2 + 4 + 7 + 14
1, 2, 4, 7, 和 14 是 28 的所有正因子。
class Solution {
    public boolean checkPerfectNumber(int num) {
        //1是任何数的因子,sum直接从1开始
        int sum = 1;
        //从2开始遍历,到num的开方结束,因为因数都是成对出现的
        //比如36--> [2,18][3,12][4,9][6,6],2~6对应的因数可以通过num除以1~6获得,当然36并不是快乐数举例而已
        for (int i = 2; i <= Math.sqrt(num); i++) {
            if (num % i == 0) {
                //加上因数本身
                sum += i;
                //加上与本身成对的因数
                sum = sum + num / i;
                //如果因数为开方时,要减去一个,不然算了两次,比如[6,6]
                if (i == Math.sqrt(num)) {
                    sum -= i;
                }
            }
        }
        //如果num等于sum,并且不等于1时返回true
        return sum == num && sum != 1;
    }
}

你可能感兴趣的:(力扣算法必刷题(周更))