LeetBook-初级算法

56 阅读1小时+

初级算法

初级算法 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

删除排序数组中的重复项

解法1

双指针(快慢指针)

  1. 快慢指针初始指向数组第一个元素
  2. 快指针对数组进行循环
  3. 如果碰到快慢指针所指向的元素不一致,则慢指针自加1,然后把快指针的值赋给慢指针指向的位置
  4. 返回慢指针自加1后的整数
class Solution {
    public int removeDuplicates(int[] nums) {
        int left = 0;
        int right;
        for (right = 0; right < nums.length; right++) {
            if (nums[left] != nums[right]) {
                nums[++left] = nums[right];
            }
        }
        return ++left;
    }
}

买卖股票的最佳时机Ⅱ

解法1

  1. 贪心算法
  2. 后大于前就加
class Solution {
    public int maxProfit(int[] prices) {
        int result = 0;
        for (int i = 0; i < prices.length - 1; i++) {
            int temp = prices[i + 1] - prices[i];
            if (temp > 0) {
                result += temp;
            }
        }
        return result;
    }
}

旋转数组

解法1

  1. 如果k大于数组长度,自减数组长度
  2. 用一个temp数组存放后面几位
  3. 将数组前面的部分移到后面
  4. 将temp里存放的数放到前面
class Solution {
    public void rotate(int[] nums, int k) {
        while (k > nums.length) {
            k -= nums.length;
        }
        int[] temp = new int[k];
        int index = 0;
        for (int i = nums.length - k; i < nums.length; i++) {
            temp[index++] = nums[i];
        }
        for (int i = nums.length - k - 1; i >= 0; i--) {
            nums[i + k] = nums[i];
        }
        for (int i = 0; i < index; i++) {
            nums[i] = temp[i];
        }
    }
}

存在重复元素

解法1

  1. 使用HashSet存放遍历过的元素
  2. 如果碰到元素已经放入HashSet中,返回true,否则返回false
class Solution {
    public boolean containsDuplicate(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < nums.length; i++) {
            if (set.contains(nums[i])) {
                return true;
            }
            set.add(nums[i]);
        }
        return false;
    }
}

解法2

解法1的基础上优化

  • 不使用contains方法,而用add方法返回值是否成功来进行判断
class Solution {
    public boolean containsDuplicate(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < nums.length; i++) {
            if (!set.add(nums[i])) {
                return true;
            }
        }
        return false;
    }
}

只出现一次的数字

解法1

  1. new一个HashMap用来存放出现过的数字和出现次数的映射
  2. 遍历一遍后map中存放了所有数字及出现次数
  3. 取出出现次数为1的key返回
class Solution {
    public int singleNumber(int[] nums) {
        int result = 0;
        for (int n : nums) {
            result ^= n;
        }
        return result;
    }
}

两个数组的交集Ⅱ

解法1

  1. 新建一个数组
  2. 遍历list1,对于list1中的每个元素,都在新数组中对应下标自增1
  3. 新建一个result数组用于存放结果
  4. 遍历list2,对于list2中每个元素,对应新数组中的下标不为0的元素存放入result数组,并把新数组中元素自减1
  5. 用Arrays的copyOfRange方法返回结果效率较高
class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        int[] temp = new int[1001];
        for (int n : nums1) {
            temp[n]++;
        }
        int[] result = new int[nums1.length];
        int index = 0;
        for (int n : nums2) {
            if (temp[n] > 0) {
                result[index++] = n;
                temp[n]--;
            }
        }
        return Arrays.copyOfRange(result, 0, index);
    }
}

加一

解法1

  1. 从后向前遍历数组,遇9变0,其余自增return
  2. 遍历结束仍没return,则return个新数组,第一位1,其余0
class Solution {
    public int[] plusOne(int[] digits) {
        for (int i = digits.length - 1; i >= 0; i--) {
            if (digits[i] == 9) {
                digits[i] = 0;
                continue;
            }
            digits[i] += 1;
            return digits;
        }
        int[] result = new int[digits.length + 1];
        result[0] = 1;
        return result;
    }
}

移动零

解法1

双指针(快慢指针)

  1. 快慢指针初始化均指向0
  2. 快指针遍历数组
  3. 如果碰到非0的数则向慢指针所指向的位置赋值,并且慢指针自加
  4. 遍历完成后,对慢指针指向位置之后的位置赋0
class Solution {
    public void moveZeroes(int[] nums) {
        int left = 0;
        for (int right = 0; right < nums.length; right++) {
            if (nums[right] != 0) {
                nums[left++] = nums[right];
            }
        }
        for (int i = left; i < nums.length; i++) {
            nums[i] = 0;
        }
    }
}

两数之和

解法1

  1. 使用HashMap遍历一遍数组(map的key为元素值,value为元素下标)
  2. 每一次遍历都求出当前元素和target的差,如果该值在map中存在,则直接返回这两个值
  3. 否则将当前元素加入到map中
class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (map.containsKey(target - nums[i])) {
                return new int[]{i, map.get(target - nums[i])};
            }
            map.put(nums[i], i);
        }
        return new int[0];
    }
}

有效的数独

解法1

  1. 对行、列、3*3方格,分别new一个HashMap数组
  2. 每个数组有9个HashMap对应9行、9列、9个box
  3. 遍历数组,将每一个元素与每一个map中的key作比较,如果出现重复,则返回false
  4. 否则返回true
class Solution {
    public boolean isValidSudoku(char[][] board) {
        Map<Integer, Integer>[] line = new HashMap[9];
        Map<Integer, Integer>[] row = new HashMap[9];
        Map<Integer, Integer>[] box = new HashMap[9];
        for (int i = 0; i < 9; i++) {
            line[i] = new HashMap<>();
            row[i] = new HashMap<>();
            box[i] = new HashMap<>();
        }
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                char gt = board[i][j];
                if (gt != '.') {
                    int n = (int)gt;
                    int box_index = (i / 3) * 3 + j / 3;
                    row[i].put(n, row[i].getOrDefault(n, 0) + 1);
                    line[j].put(n, line[j].getOrDefault(n, 0) + 1);
                    box[box_index].put(n, box[box_index].getOrDefault(n, 0) + 1);
                    if (row[i].get(n) > 1 || line[j].get(n) > 1 || box[box_index].get(n) > 1) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
}

解法2 位运算

位运算

class Solution {
    public boolean isValidSudoku(char[][] board) {
        int[] row = new int[10];
        int[] line = new int[10];
        int[] box = new int[10];
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                char c = board[i][j];
                if (c == '.') {
                    continue;
                }
                int n = c - '0';
                int box_index = (i / 3) * 3 + j / 3;
                if ((((row[i] >> n) & 1) == 1) || (((line[j] >> n) & 1) == 1) || (((box[box_index] >> n) & 1) == 1)) {
                    return false;
                }
                row[i] |= (1<<n);
                line[j] |= (1<<n);
                box[box_index] |= (1<<n);
            }
        }
        return true;
    }
}

旋转图像

解法1

  1. 如果是顺时针旋转90°

    一定是先对角线翻转,再水平翻转

  2. 如果是逆时针旋转90°

    一定是先水平翻转,再对角线翻转

class Solution {
    public void rotate(int[][] matrix) {
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix.length - 1 - i; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[matrix.length - 1 - j][matrix.length - 1 - i];
                matrix[matrix.length - 1 - j][matrix.length - 1 - i] = temp;
            }
        }
        for (int i = 0; i < matrix.length / 2; i++) {
            int[] t = matrix[i];
            matrix[i] = matrix[matrix.length - 1 - i];
            matrix[matrix.length - 1 - i] = t;
        }
    }
}

反转字符串

解法1

双指针

  1. 一个指针指向数组开头,另一个指针指向数组末尾
  2. 循环交换,当两个指针相遇时结束
class Solution {
    public void reverseString(char[] s) {
        int left = 0;
        int right = s.length - 1;
        while (left < right) {
            char temp = s[left];
            s[left] = s[right];
            s[right] = temp;
            left++;
            right--;
        }
    }
}

整数反转

解法1

  1. 将每次x%10的结果加到result,然后自乘10
  2. 如果越界返回0
class Solution {
    public int reverse(int x) {
        int result = 0;
        int temp = 0;
        while (x != 0) {
            temp = result;
            result = result * 10 + x % 10;
            if ((result - x % 10) / 10 != temp) {
                return 0;
            }
            x = x / 10;
        }
        return result;
    }
}

字符串中的第一个唯一字符

解法1

  1. 将字符串转为char数组,新建一个hashmap用于存放char和对应的下标
  2. 遍历数组,将每一个char和对应的下标放入到hashmap
  3. 如果当前char在hashmap中存在,则将下标置为-1
  4. 遍历hashmap,取出下标不为1的最小值返回
class Solution {
    public int firstUniqChar(String s) {
        int[] temp = new int[26];
        char[] ccc = s.toCharArray();
        for (char c : ccc) {
            temp[c - 97]++;
        }
        for (int i = 0; i < ccc.length; i++) {
            if (temp[ccc[i] - 97] == 1) {
                return i;
            }
        }
        return -1;
    }
}

有效的字母异位词

解法1

  1. 将每个字符串排序后放入一个新的字符串数组,与原数组对应
  2. 遍历原数组
  3. 如果对应的排序后的数组对应值存在在map中,则将原数组的元素添加到map的value(List)里
  4. 如果不存在,则将原数组元素作为key,新数组元素作为value(放入list),put进map
  5. 遍历map取出所有value放入result(List)返回
class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        String[] newstr = new String[strs.length];
        List<List<String>> result = new ArrayList<>();
        Map<String, List<String>> map = new HashMap<>();
        for (int i = 0; i < strs.length; i++) {
            char[] ss = strs[i].toCharArray();
            Arrays.sort(ss);
            newstr[i] = String.valueOf(ss);
        }
        for (int i = 0; i < strs.length; i++) {
            if (map.containsKey(newstr[i])) {
                map.get(newstr[i]).add(strs[i]);
                continue;
            }
            List<String> list = new ArrayList<>();
            list.add(strs[i]);
            map.put(newstr[i], list);
        }
        // Iterator iterator = map.keySet().iterator();
        for (Map.Entry<String, List<String>> entry : map.entrySet()) {
            result.add(entry.getValue());
        }
        return result;
    }
}

解法2

  1. 遍历字符串数组
  2. 将元素排序,并在map中get元素的value
  3. 如果value为null,则将字符串和对应的ArrayList(空的)放入map中,并将ArrayList放入result中
  4. 向ArrayList中添加元素
  5. 返回result
class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        List<List<String>> result = new ArrayList<>();
        Map<String, ArrayList<String>> map = new HashMap<>();
        char[] ccc;
        String sss;
        ArrayList<String> temp = null;
        for (String str : strs) {
            ccc = str.toCharArray();
            Arrays.sort(ccc);
            sss = String.valueOf(ccc);
            temp = map.get(sss);
            if (temp == null) {
                temp = new ArrayList<>();
                map.put(sss, temp);
                result.add(temp);
            }
            temp.add(str);
        }
        return result;
    }
}

验证回文串

解法1

  1. 字符串的replaseAll方法,正则表达式匹配替换
  2. toLowerCase方法转小写
  3. 放入插入数组
  4. 双指针分别从前后遍历
  5. 如果不相等返回false,否则返回true
class Solution {
    public boolean isPalindrome(String s) {
        s = s.replaceAll("[^a-zA-Z0-9]", "").toLowerCase();
        char[] c = s.toCharArray();
        int left = 0; 
        int right = c.length - 1;
        while (left < right) {
            if (c[left] != c[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

解法2

  1. 解法1的基础上优化
  2. 不使用replaceAll方法,使用isLetterOrDigit方法,如果碰到非数字字母跳过
  3. 如果前后不相等返回false,否则返回true
class Solution {
    public boolean isPalindrome(String s) {
        char[] c = s.toCharArray();
        int left = 0; 
        int right = c.length - 1;
        while (left < right) {
            if (!Character.isLetterOrDigit(c[left])) {
                left++;
                continue;
            }
            if (!Character.isLetterOrDigit(c[right])) {
                right--;
                continue;
            }
            if (Character.toLowerCase(c[left]) != Character.toLowerCase(c[right])) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

字符串转整数(atoi)

解法1

if-else太难了

大佬写的

class Solution {
    public int myAtoi(String str) {
        str = str.trim();//去掉前后的空格
        //如果为空,直接返回0
        if (str.length() == 0)
            return 0;
        int index = 0;//遍历字符串中字符的位置
        int res = 0;//最终结果
        int sign = 1;//符号,1是正数,-1是负数,默认为正数
        int length = str.length();
        //判断符号
        if (str.charAt(index) == '-' || str.charAt(index) == '+')
            sign = str.charAt(index++) == '+' ? 1 : -1;
        for (; index < length; ++index) {
            //取出字符串中字符,然后转化为数字
            int digit = str.charAt(index) - '0';
            //按照题中的要求,读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。
            //字符串的其余部分将被忽略。如果读取了非数字,后面的都要忽略
            if (digit < 0 || digit > 9)
                break;
            //越界处理
            if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE / 10 && digit > Integer.MAX_VALUE % 10))
                return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
            else
                res = res * 10 + digit;
        }
        return sign * res;
    }
}

实现strStr()

解法1

  1. 将字符串转化为数组
  2. 对长数组进行循环,分别于短数组的第一个字母进行比较
    • 如果相等,则进行一个长度为短数组长度的循环,比较两个数组的元素是否相等
      • 如果循环内没有出现不相等的情况,则return返回下标
      • 如果出现不相等则break,进入最外层循环继续进行
    • 如果不相等,则继续循环
  3. 如果没循环到的长数组元素个数少于短数组长度,则提前跳出
class Solution {
    public int strStr(String haystack, String needle) {
        int len1 = haystack.length();
        int len2 = needle.length();
        char[] s1 = haystack.toCharArray();
        char[] s2 = needle.toCharArray();
        for (int i = 0; i < len1; i++) {
            if (len1 - i < len2) {
                break;
            }
            if (s1[i] == s2[0]) {
                boolean flag = true;
                for (int j = i; j < i + len2; j++) {
                    if (s1[j] != s2[j - i]) {
                        flag = false;
                        break;
                    }
                }
                if (flag) {
                    return i;
                }
            }
        }
        return -1;
    }
}

外观数列

解法1

这居然是官解....................................

class Solution {
    public String countAndSay(int n) {
        String[] arr = {
            "","1","11","21","1211","111221","312211","13112221","1113213211","31131211131221","13211311123113112211","11131221133112132113212221","3113112221232112111312211312113211","1321132132111213122112311311222113111221131221","11131221131211131231121113112221121321132132211331222113112211","311311222113111231131112132112311321322112111312211312111322212311322113212221","132113213221133112132113311211131221121321131211132221123113112221131112311332111213211322211312113211","11131221131211132221232112111312212321123113112221121113122113111231133221121321132132211331121321231231121113122113322113111221131221","31131122211311123113321112131221123113112211121312211213211321322112311311222113311213212322211211131221131211132221232112111312111213111213211231131122212322211331222113112211","1321132132211331121321231231121113112221121321132122311211131122211211131221131211132221121321132132212321121113121112133221123113112221131112311332111213122112311311123112111331121113122112132113213211121332212311322113212221","11131221131211132221232112111312111213111213211231132132211211131221131211221321123113213221123113112221131112311332211211131221131211132211121312211231131112311211232221121321132132211331121321231231121113112221121321133112132112312321123113112221121113122113121113123112112322111213211322211312113211","311311222113111231133211121312211231131112311211133112111312211213211312111322211231131122211311122122111312211213211312111322211213211321322113311213212322211231131122211311123113223112111311222112132113311213211221121332211211131221131211132221232112111312111213111213211231132132211211131221232112111312211213111213122112132113213221123113112221131112311311121321122112132231121113122113322113111221131221","132113213221133112132123123112111311222112132113311213211231232112311311222112111312211311123113322112132113213221133122112231131122211211131221131112311332211211131221131211132221232112111312111213322112132113213221133112132113221321123113213221121113122123211211131221222112112322211231131122211311123113321112131221123113111231121113311211131221121321131211132221123113112211121312211231131122211211133112111311222112111312211312111322211213211321322113311213211331121113122122211211132213211231131122212322211331222113112211","111312211312111322212321121113121112131112132112311321322112111312212321121113122112131112131221121321132132211231131122211331121321232221121113122113121113222123112221221321132132211231131122211331121321232221123113112221131112311332111213122112311311123112112322211211131221131211132221232112111312211322111312211213211312111322211231131122111213122112311311221132211221121332211213211321322113311213212312311211131122211213211331121321123123211231131122211211131221131112311332211213211321223112111311222112132113213221123123211231132132211231131122211311123113322112111312211312111322212321121113122123211231131122113221123113221113122112132113213211121332212311322113212221","3113112221131112311332111213122112311311123112111331121113122112132113121113222112311311221112131221123113112221121113311211131122211211131221131211132221121321132132212321121113121112133221123113112221131112311332111213213211221113122113121113222112132113213221232112111312111213322112132113213221133112132123123112111311222112132113311213211221121332211231131122211311123113321112131221123113112221132231131122211211131221131112311332211213211321223112111311222112132113212221132221222112112322211211131221131211132221232112111312111213111213211231132132211211131221232112111312211213111213122112132113213221123113112221133112132123222112111312211312112213211231132132211211131221131211132221121311121312211213211312111322211213211321322113311213212322211231131122211311123113321112131221123113112211121312211213211321222113222112132113223113112221121113122113121113123112112322111213211322211312113211","132113213221133112132123123112111311222112132113311213211231232112311311222112111312211311123113322112132113212231121113112221121321132132211231232112311321322112311311222113111231133221121113122113121113221112131221123113111231121123222112132113213221133112132123123112111312111312212231131122211311123113322112111312211312111322111213122112311311123112112322211211131221131211132221232112111312111213111213211231132132211211131221232112111312212221121123222112132113213221133112132123123112111311222112132113213221132213211321322112311311222113311213212322211211131221131211221321123113213221121113122113121132211332113221122112133221123113112221131112311332111213122112311311123112111331121113122112132113121113222112311311221112131221123113112221121113311211131122211211131221131211132221121321132132212321121113121112133221123113112221131112212211131221121321131211132221123113112221131112311332211211133112111311222112111312211311123113322112111312211312111322212321121113121112133221121321132132211331121321231231121113112221121321132122311211131122211211131221131211322113322112111312211322132113213221123113112221131112311311121321122112132231121113122113322113111221131221","1113122113121113222123211211131211121311121321123113213221121113122123211211131221121311121312211213211321322112311311222113311213212322211211131221131211221321123113213221121113122113121113222112131112131221121321131211132221121321132132211331121321232221123113112221131112311322311211131122211213211331121321122112133221121113122113121113222123211211131211121311121321123113111231131122112213211321322113311213212322211231131122211311123113223112111311222112132113311213211221121332211231131122211311123113321112131221123113111231121113311211131221121321131211132221123113112211121312211231131122113221122112133221121113122113121113222123211211131211121311121321123113213221121113122113121113222113221113122113121113222112132113213221232112111312111213322112311311222113111221221113122112132113121113222112311311222113111221132221231221132221222112112322211213211321322113311213212312311211131122211213211331121321123123211231131122211211131221131112311332211213211321223112111311222112132113213221123123211231132132211231131122211311123113322112111312211312111322111213122112311311123112112322211213211321322113312211223113112221121113122113111231133221121321132132211331121321232221123123211231132132211231131122211331121321232221123113112221131112311332111213122112311311123112112322211211131221131211132221232112111312111213111213211231132132211211131221131211221321123113213221123113112221131112211322212322211231131122211322111312211312111322211213211321322113311213211331121113122122211211132213211231131122212322211331222113112211","31131122211311123113321112131221123113111231121113311211131221121321131211132221123113112211121312211231131122211211133112111311222112111312211312111322211213211321322123211211131211121332211231131122211311122122111312211213211312111322211231131122211311123113322112111331121113112221121113122113111231133221121113122113121113222123211211131211121332211213211321322113311213211322132112311321322112111312212321121113122122211211232221123113112221131112311332111213122112311311123112111331121113122112132113311213211321222122111312211312111322212321121113121112133221121321132132211331121321132213211231132132211211131221232112111312212221121123222112132113213221133112132123123112111311222112132113311213211231232112311311222112111312211311123113322112132113212231121113112221121321132122211322212221121123222112311311222113111231133211121312211231131112311211133112111312211213211312111322211231131122211311123113322113223113112221131112311332211211131221131211132211121312211231131112311211232221121321132132211331221122311311222112111312211311123113322112132113213221133122211332111213112221133211322112211213322112111312211312111322212321121113121112131112132112311321322112111312212321121113122112131112131221121321132132211231131122211331121321232221121113122113121122132112311321322112111312211312111322211213111213122112132113121113222112132113213221133112132123222112311311222113111231132231121113112221121321133112132112211213322112111312211312111322212311222122132113213221123113112221133112132123222112111312211312111322212321121113121112133221121311121312211213211312111322211213211321322123211211131211121332211213211321322113311213212312311211131122211213211331121321122112133221123113112221131112311332111213122112311311123112111331121113122112132113121113222112311311222113111221221113122112132113121113222112132113213221133122211332111213322112132113213221132231131122211311123113322112111312211312111322212321121113122123211231131122113221123113221113122112132113213211121332212311322113212221","13211321322113311213212312311211131122211213211331121321123123211231131122211211131221131112311332211213211321223112111311222112132113213221123123211231132132211231131122211311123113322112111312211312111322111213122112311311123112112322211213211321322113312211223113112221121113122113111231133221121321132132211331121321232221123123211231132132211231131122211331121321232221123113112221131112311332111213122112311311123112112322211211131221131211132221232112111312211322111312211213211312111322211231131122111213122112311311221132211221121332211213211321322113311213212312311211131122211213211331121321123123211231131122211211131221232112111312211312113211223113112221131112311332111213122112311311123112112322211211131221131211132221232112111312211322111312211213211312111322211231131122111213122112311311221132211221121332211211131221131211132221232112111312111213111213211231132132211211131221232112111312211213111213122112132113213221123113112221133112132123222112111312211312112213211231132132211211131221131211322113321132211221121332211213211321322113311213212312311211131122211213211331121321123123211231131122211211131221131112311332211213211321322113311213212322211322132113213221133112132123222112311311222113111231132231121113112221121321133112132112211213322112111312211312111322212311222122132113213221123113112221133112132123222112111312211312111322212311322123123112111321322123122113222122211211232221123113112221131112311332111213122112311311123112111331121113122112132113121113222112311311221112131221123113112221121113311211131122211211131221131211132221121321132132212321121113121112133221123113112221131112212211131221121321131211132221123113112221131112311332211211133112111311222112111312211311123113322112111312211312111322212321121113121112133221121321132132211331121321132213211231132132211211131221232112111312212221121123222112311311222113111231133211121321321122111312211312111322211213211321322123211211131211121332211231131122211311123113321112131221123113111231121123222112111331121113112221121113122113111231133221121113122113121113221112131221123113111231121123222112111312211312111322212321121113121112131112132112311321322112111312212321121113122122211211232221121321132132211331121321231231121113112221121321133112132112312321123113112221121113122113111231133221121321132132211331221122311311222112111312211311123113322112111312211312111322212311322123123112112322211211131221131211132221132213211321322113311213212322211231131122211311123113321112131221123113112211121312211213211321222113222112132113223113112221121113122113121113123112112322111213211322211312113211","11131221131211132221232112111312111213111213211231132132211211131221232112111312211213111213122112132113213221123113112221133112132123222112111312211312112213211231132132211211131221131211132221121311121312211213211312111322211213211321322113311213212322211231131122211311123113223112111311222112132113311213211221121332211211131221131211132221231122212213211321322112311311222113311213212322211211131221131211132221232112111312111213322112131112131221121321131211132221121321132132212321121113121112133221121321132132211331121321231231121113112221121321133112132112211213322112311311222113111231133211121312211231131122211322311311222112111312211311123113322112132113212231121113112221121321132122211322212221121123222112111312211312111322212321121113121112131112132112311321322112111312212321121113122112131112131221121321132132211231131122111213122112311311222113111221131221221321132132211331121321231231121113112221121321133112132112211213322112311311222113111231133211121312211231131122211322311311222112111312211311123113322112132113212231121113112221121321132122211322212221121123222112311311222113111231133211121312211231131112311211133112111312211213211312111322211231131122111213122112311311222112111331121113112221121113122113121113222112132113213221232112111312111213322112311311222113111221221113122112132113121113222112311311222113111221132221231221132221222112112322211211131221131211132221232112111312111213111213211231132132211211131221232112111312211213111213122112132113213221123113112221133112132123222112111312211312111322212321121113121112133221132211131221131211132221232112111312111213322112132113213221133112132113221321123113213221121113122123211211131221222112112322211231131122211311123113321112132132112211131221131211132221121321132132212321121113121112133221123113112221131112311332111213211322111213111213211231131211132211121311222113321132211221121332211213211321322113311213212312311211131122211213211331121321123123211231131122211211131221131112311332211213211321223112111311222112132113213221123123211231132132211231131122211311123113322112111312211312111322111213122112311311123112112322211213211321322113312211223113112221121113122113111231133221121321132132211331121321232221123123211231132132211231131122211331121321232221123113112221131112311332111213122112311311123112112322211211131221131211132221232112111312211322111312211213211312111322211231131122111213122112311311221132211221121332211213211321322113311213212312311211131211131221223113112221131112311332211211131221131211132211121312211231131112311211232221121321132132211331121321231231121113112221121321133112132112211213322112312321123113213221123113112221133112132123222112311311222113111231132231121113112221121321133112132112211213322112311311222113111231133211121312211231131112311211133112111312211213211312111322211231131122111213122112311311221132211221121332211211131221131211132221232112111312111213111213211231132132211211131221232112111312211213111213122112132113213221123113112221133112132123222112111312211312111322212311222122132113213221123113112221133112132123222112311311222113111231133211121321132211121311121321122112133221123113112221131112311332211322111312211312111322212321121113121112133221121321132132211331121321231231121113112221121321132122311211131122211211131221131211322113322112111312211322132113213221123113112221131112311311121321122112132231121113122113322113111221131221","3113112221131112311332111213122112311311123112111331121113122112132113121113222112311311221112131221123113112221121113311211131122211211131221131211132221121321132132212321121113121112133221123113112221131112212211131221121321131211132221123113112221131112311332211211133112111311222112111312211311123113322112111312211312111322212321121113121112133221121321132132211331121321132213211231132132211211131221232112111312212221121123222112311311222113111231133211121321321122111312211312111322211213211321322123211211131211121332211231131122211311123113321112131221123113111231121123222112111331121113112221121113122113111231133221121113122113121113221112131221123113111231121123222112111312211312111322212321121113121112131112132112311321322112111312212321121113122122211211232221121321132132211331121321231231121113112221121321132132211322132113213221123113112221133112132123222112111312211312112213211231132132211211131221131211322113321132211221121332211231131122211311123113321112131221123113111231121113311211131221121321131211132221123113112211121312211231131122211211133112111311222112111312211312111322211213211321223112111311222112132113213221133122211311221122111312211312111322212321121113121112131112132112311321322112111312212321121113122122211211232221121321132132211331121321231231121113112221121321132132211322132113213221123113112221133112132123222112111312211312112213211231132132211211131221131211322113321132211221121332211213211321322113311213212312311211131122211213211331121321123123211231131122211211131221131112311332211213211321223112111311222112132113213221123123211231132132211231131122211311123113322112111312211312111322111213122112311311123112112322211213211321322113312211223113112221121113122113111231133221121321132132211331222113321112131122211332113221122112133221123113112221131112311332111213122112311311123112111331121113122112132113121113222112311311221112131221123113112221121113311211131122211211131221131211132221121321132132212321121113121112133221123113112221131112311332111213122112311311123112112322211322311311222113111231133211121312211231131112311211232221121113122113121113222123211211131221132211131221121321131211132221123113112211121312211231131122113221122112133221121321132132211331121321231231121113121113122122311311222113111231133221121113122113121113221112131221123113111231121123222112132113213221133112132123123112111312211322311211133112111312211213211311123113223112111321322123122113222122211211232221121113122113121113222123211211131211121311121321123113213221121113122123211211131221121311121312211213211321322112311311222113311213212322211211131221131211221321123113213221121113122113121113222112131112131221121321131211132221121321132132211331121321232221123113112221131112311322311211131122211213211331121321122112133221121113122113121113222123112221221321132132211231131122211331121321232221121113122113121113222123211211131211121332211213111213122112132113121113222112132113213221232112111312111213322112132113213221133112132123123112111311222112132113311213211221121332211231131122211311123113321112131221123113112221132231131122211211131221131112311332211213211321223112111311222112132113212221132221222112112322211211131221131211132221232112111312111213111213211231131112311311221122132113213221133112132123222112311311222113111231132231121113112221121321133112132112211213322112111312211312111322212321121113121112131112132112311321322112111312212321121113122122211211232221121311121312211213211312111322211213211321322123211211131211121332211213211321322113311213211322132112311321322112111312212321121113122122211211232221121321132132211331121321231231121113112221121321133112132112312321123113112221121113122113111231133221121321132122311211131122211213211321222113222122211211232221123113112221131112311332111213122112311311123112111331121113122112132113121113222112311311221112131221123113112221121113311211131122211211131221131211132221121321132132212321121113121112133221123113112221131112311332111213213211221113122113121113222112132113213221232112111312111213322112132113213221133112132123123112111312211322311211133112111312212221121123222112132113213221133112132123222113223113112221131112311332111213122112311311123112112322211211131221131211132221232112111312111213111213211231132132211211131221131211221321123113213221123113112221131112211322212322211231131122211322111312211312111322211213211321322113311213211331121113122122211211132213211231131122212322211331222113112211"
        };
        return arr[n];
    }
}

解法2

  1. 遍历
class Solution {
    public String countAndSay(int n) {
        String str = "1";
        for (int i = 2; i <= n; ++i) {
            StringBuilder sb = new StringBuilder();
            int start = 0;
            int pos = 0;

            while (pos < str.length()) {
                while (pos < str.length() && str.charAt(pos) == str.charAt(start)) {
                    pos++;
                }
                sb.append(Integer.toString(pos - start)).append(str.charAt(start));
                start = pos;
            }
            str = sb.toString();
        }
        
        return str;
    }
}

最长公共前缀

解法1

  1. 找到字符串最大长度和最小长度
  2. 将字符串转化为数组
  3. 遍历数组每一位,当遇到某一位出现不同时跳出
  4. 返回结果
class Solution {
    public String longestCommonPrefix(String[] strs) {
        int maxit = 0;
        int minit = 999;
        for (String ss: strs) {
            if (ss.length() > maxit) {
                maxit = ss.length();
            }
            if (ss.length() < minit) {
                minit = ss.length();
            }
        }
        char[][] s = new char[strs.length][maxit];
        String result = "";
        for (int i = 0; i < s.length; i++) {
            s[i] = strs[i].toCharArray();
        }
        boolean flag = true;
        for (int i = 0; i < minit; i++) {
            for (int j = 0; j < s.length - 1; j++) {
                if (s[j][i] != s[j + 1][i]) {
                    flag = false;
                    break;
                }
            }
            if (flag == false) {
                break;
            }
            result = result + s[0][i];
        }
        return result;
    }
}

解法2

  1. 遍历数组,找出长度最小的字符串
  2. 对找出的字符串进行循环由大到小切割
  3. 判断切割下来的子串是否为所有字符串的公共前缀
  4. 若为公共前缀则返回此子串,若循环到最后依然没有匹配,则返回空串
class Solution {
    public String longestCommonPrefix(String[] strs) {
        String minit = strs[0];
        for (int i = 1; i < strs.length; i++) {
            if (strs[i].length() < minit.length()) {
                minit = strs[i];
            }
        }
        for (int i = 0; i < minit.length(); i++) {
            String s = minit.substring(0, minit.length() - i);
            int count = 0;
            for (int j = 0; j < strs.length; j++) {
                if (strs[j].indexOf(s) == 0) {
                    count++;
                }
            }
            if (count == strs.length) {
                return s;
            }
        }
        return "";
    }
}

删除链表中的节点

解法1

大佬非常有意思的解答:

目标:杀掉A

  • 正常杀手需要找到A的把柄才可以杀掉A,
  • 可现在找到A本人后竟然没有可以获取A把柄的途径
  • A得知我们要杀他,心生一计,可助你完成任务
  • A说我有B的把柄,你杀了B,我改头换面,以B的身份活着
  • GC也会自动清理掉B的尸体,没人会知道的
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public void deleteNode(ListNode node) {
        node.val = node.next.val;
        node.next = node.next.next;
    }
}

删除链表的倒数第N个节点

解法1

  1. 先循环一次链表求得链表的size
  2. 第二次循环链表到要删除的元素的前一个元素
  3. node的next指向node.next.next
  4. 两种特殊情况:
  • 注意1,当只有一个节点时直接给头节点赋null
  • 注意2,当删除的为头节点时,头节点直接指向下一个元素
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        int size = 1;
        ListNode node = head;
        while (node.next != null) {
            node = node.next;
            size++;
        }
        if (head.next == null) {
            head = null;
            return head;
        }
        if (size == n) {
            head = head.next;
            return head;
        }
        node = head;
        for (int i = 1; i < size - n; i++) {
            node = node.next;
        }
        node.next = node.next.next;
        return head;
    }
}

解法2

快慢指针

  1. 快慢指针初始化均指向head
  2. 快指针先移动
  3. 当快指针和慢指针之间的距离等于n(要删除倒数第n个结点)时,快慢指针同时移动到最后
  4. 移除慢指针的next元素
  5. 判断两个特殊情况:
  • 当只有一个结点时,头节点指向null,然后返回
  • 当删除的为头节点时,头节点直接指向下一个元素
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode node = head;
        ListNode slow = head;
        int count = 0;
        if (head.next == null) {
            head = null;
            return head;
        }
        while (node.next != null) {
            node = node.next;
            count++;
            if (count <= n) {
                continue;
            }
            slow = slow.next;
        }
        if (count + 1 == n) {
            head = head.next;
            return head;
        }
        slow.next = slow.next.next;
        return head;
    }
}

反转链表

解法1

  1. node初始指向头节点
  2. 当node的next不为空时,将node的每一个next节点链到head,并让head指向新来的节点
  3. 当node移动到最后,链表反转完成
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode node = head;
        ListNode temp = null;
        while (node.next != null) {
            temp = node.next;
            node.next = node.next.next;
            temp.next = head;
            head = temp;
        }
        return head;
    }
}

合并两个有序链表

解法1

  1. 取出两个链表头节点中小的那个作为新链表的头节点
  2. 同时遍历两个链表,将两个链表头节点小的那个连接到新链表的末尾,并将原头节点指向头节点的next
  3. 当一个链表循环至空时,将另一个链表剩余部分直接连到新链表的末尾
  • 注意:当传入某个链表为空时直接返回另一个链表
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if (list2 == null) {
            return list1;
        }
        if  (list1 == null) {
            return list2;
        }
        ListNode temp1 = null;
        ListNode temp2 = null;
        ListNode head = null;
        if (list1.val > list2.val) {
            head = list2;
            list2 = list2.next;
        } else {
            head = list1;
            list1 = list1.next;
        }
        ListNode temp = head;
        while (list1 != null && list2 != null) {
            if (list1.val > list2.val) {
                temp2 = list2.next;
                temp.next = list2;
                temp = temp.next;
                list2 = temp2;
            } else {
                temp1 = list1.next;
                temp.next = list1;
                temp = temp.next;
                list1 = temp1;
            }
        }
        if (list1 != null) {
            temp.next = list1;
        }
        if (list2 != null) {
            temp.next = list2;
        }
        return head;
    }
}

回文链表

解法1

暴力循环,丢到数组判断

  1. 循环链表取出所有值丢到数组里
  2. 数组双指针前后循环判断是否有不相等的
  3. 如果有不相等的返回false,否则返回true
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public boolean isPalindrome(ListNode head) {
        int count = 0;
        ListNode node = head;
        int[] nums = new int[999999];
        while (node.next != null) {
            nums[count] = node.val;
            count++;
            node = node.next;
        }
        nums[count] = node.val;
        int left = 0;
        int right = count;
        while (left < right) {
            if (nums[left] != nums[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

解法2

使用栈

  1. 遍历一次链表,将链表中的元素放到一个栈中
  2. 逐一取出栈中的元素,并且遍历链表,如果碰到不相等的值,返回false
  3. 否则返回true
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public boolean isPalindrome(ListNode head) {
        Stack<Integer> stack = new Stack();
        ListNode node = head;
        while (node != null) {
            stack.push(node.val);
            node = node.next;
        }
        while (head != null) {
            if (head.val != stack.pop()) {
                return false;
            }
            head = head.next;
        }
        return true;
    }
}

解法3

快慢指针加反转链表

  1. 快指针步长2,慢指针步长1遍历链表
  2. 当快指针到末尾时,翻转慢指针后面的链表
  3. 快指针移动到开头
  4. 快慢指针同时以步长1进行遍历,快指针遍历前半链表,慢指针遍历后半链表
  5. 如果有值不相等,返回false,否则返回true
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public boolean isPalindrome(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        if (fast != null) {
            slow = slow.next;
        }
        slow = reverseList(slow);
        fast = head;
        while (slow != null) {
            if (slow.val != fast.val) {
                return false;
            }
            slow = slow.next;
            fast = fast.next;
        }
        return true;
    }
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode node = head;
        ListNode i = null;
        while (node.next != null) {
            i = node.next;
            node.next = node.next.next;
            i.next = head;
            head = i;
        }
        return head;
    }
}

解法4

  1. 第一次遍历,拿到链表长度,并求得中间长度
  2. 第二次遍历前半部分,将nodeM节点指针指向中间节点
  3. 第三次遍历后半部分,将指针顺序调转(即前半个链表正常,后半个链表头节点为原来的末尾,反向到原来链表的中间)
  4. 两个链表分别遍历,如果碰到不相等返回false,否则返回true
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public boolean isPalindrome(ListNode head) {
        int count = 0;
        ListNode node = head;
        while (node != null) {
            count++;
            node = node.next;
        }
        ListNode nodeM = head;
        int mid = count / 2;
        for (int i = 0; i < mid; i++) {
            nodeM = nodeM.next;
        }
        ListNode tail = null;
        while (nodeM != null) {
            ListNode next = nodeM.next;
            nodeM.next = tail;
            tail = nodeM;
            nodeM = next;
        }
        while (head != null && tail != null) {
            if (head.val != tail.val) {
                return false;
            }
            head = head.next;
            tail = tail.next;
        }
        return true;
    }
}

环形链表

解法1

双指针(快慢指针)

  1. 快指针步长2,慢指针步长1
  2. 对链表进行循环
    • 如果相遇,则有环
    • 如果快指针碰到末尾,则无环
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null) {
            return false;
        }
        ListNode slow = head;
        ListNode fast = head;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                return true;
            }
        }
        return false;
    }
}

二叉树的最大深度

解法1

  1. 复用二叉树的层序遍历,里面有现成的level
  2. 定义一个le,当level大于le的时候给le赋值
  3. 返回层数
/**
 * 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 {
    int le = 0;
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return le;
        }
        levelOrder(root, 0);
        return le + 1;
    }
    public void levelOrder(TreeNode node, int level) {
        if (node == null) {
            return;
        }
        if (le < level) {
            le = level;
        }
        levelOrder(node.left, level + 1);
        levelOrder(node.right, level + 1);
    } 
}

验证二叉搜索树

解法1

  1. 递归判断左小右大
  • 坑点:
    • 注意递归不要只比较当前节点的左右,还要注意左小都小,右大都大
    • 有人给测试用例塞了个2147483647,绝了,习惯性用999999😂猛栽
/**
 * 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 isValidBST(TreeNode root) {
        return isT(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }
    public boolean isT(TreeNode node, long min, long max) {
        if (node == null) {
            return true;
        }
        if (node.val >= max || node.val <= min) {
            return false;
        }
        return isT(node.left, min, node.val) && isT(node.right, node.val, max);
    }
}

对称二叉树

解法1

  1. 递归
  2. 取两个根节点(一个root两遍)进行遍历
  3. 一个树的左节点是否和右节点相等,酱紫判断,
  4. 如果node1的左不等于node2的右就返回false
  5. return结果
/**
 * 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 isSymmetric(TreeNode root) {
        return isT(root, root);
    }
    public boolean isT(TreeNode node1, TreeNode node2) {
        if (node1 == null) {
            if (node2 == null) {
                return true;
            }
            return false;
        }
        if (node2 == null) {
            return false;
        }
        return (node1.val == node2.val) && isT(node1.left, node2.right) && isT(node1.right, node2.left);
    }
}

二叉树的层序遍历

解法1

  1. 递归
  2. 每层遍历都有一个level
  3. 如果当前level没有对应的list则往list中add一个ArrayList
  4. 每层从左至右,依次add进入当前level对应的list
/**
 * 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 List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        levelO(result, root, 0);
        return result;
    }
    public void levelO(List<List<Integer>> result, TreeNode node, int level) {
        if (node == null) {
            return;
        }
        if (level >= result.size()) {
            result.add(new ArrayList<>());
        }
        result.get(level).add(node.val);
        levelO(result, node.left, level + 1);
        levelO(result, node.right, level + 1);
    }
}

将有序数组转换为二叉搜索树

解法1

  1. 有序数组,每次取中点,即为当前节点
  2. 左右节点分别从中间切开的左右两个数组取中点
  3. 依次递归
/**
 * 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 TreeNode sortedArrayToBST(int[] nums) {
        if (nums.length == 0) {
            return null;
        }
        return createTreeNode(nums, 0, nums.length - 1);
    }
    public TreeNode createTreeNode(int[] nums, int start, int end) {
        if (start > end) {
            return null;
        }
        int mid = start + (end - start) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = createTreeNode(nums, start, mid - 1);
        root.right = createTreeNode(nums, mid + 1, end);
        return root;
    }
}

合并两个有序数组

解法1

  1. 尾插法
  2. m和n向前遍历,大的插入nums1的最后
  3. 循环结束,将nums1和nums2剩余的数组插入nums1前面位置
class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int tail = nums1.length - 1;
        m--;
        n--;
        while(n >= 0 && m >= 0) {
            if (nums1[m] >= nums2[n]) {
                nums1[tail--] = nums1[m--];
            } else {
                nums1[tail--] = nums2[n--];
            }
        }
        while (m >= 0) {
            nums1[tail--] = nums1[m--];
        }
        while (n >= 0) {
            nums1[tail--] = nums2[n--];
        }
    }
}

第一个错误版本

解法1

二分查找

/* The isBadVersion API is defined in the parent class VersionControl.
      boolean isBadVersion(int version); */

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        int left = 1;
        int right = n;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (!isBadVersion(mid - 1) && isBadVersion(mid)) {
                return mid;
            } else if (isBadVersion(mid)) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return 0;
    }
}

解法2

解法1的基础优化

  • 如果求第一个错误版本,那么取到正确版本就给left赋值mid + 1,循环结束后left即为第一个错误版本
/* The isBadVersion API is defined in the parent class VersionControl.
      boolean isBadVersion(int version); */

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        int left = 1;
        int right = n;
        int mid = 0;
        while (left < right) {
            mid = left + (right - left) / 2;
            if (isBadVersion(mid)) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }
}

爬楼梯

思路

  • 斐波那契数列,解法很多

  • 简单暴力递归,n给大了会超时

  • 如果使用递归也可以使用尾递归

  • 非递归解法为解法1

  • 也有相应的公式可以使用

class Solution {
    int result = 0;
    public int climbStairs(int n) {
        payapa(0, n);
        return result;
    }
    public void payapa(int now, int n) {
        if (now == n) {
            result++;
            return;
        }
        if (now > n) {
            return;
        }
        payapa(now + 1, n);
        payapa(now + 2, n);
    }
}

解法1

  • 非递归斐波那契数列
class Solution {
    public int climbStairs(int n) {
        if (n <= 1) {
            return 1;
        }
        int[] dp = new int[n];
        dp[0] = 1;
        dp[1] = 2;
        for (int i = 2; i < n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n - 1];
    }
}

买卖股票的最佳时机

想暴力玩玩,没跑通,超时了😂

class Solution {
    public int maxProfit(int[] prices) {
        int result = 0;
        for (int i = 0; i < prices.length; i++) {
            for (int j = i + 1; j < prices.length; j++) {
                if (prices[j] > prices[i]) {
                    if (prices[j] - prices[i] > result) {
                        result = prices[j] - prices[i];
                    }
                }
            }
        }
        return result;
    }
}

解法1

  1. 双指针
  2. 左指针一直指向目前的最小元素
  3. 右指针遍历数组,当碰到更小元素,让左指针指向当前元素
  4. 每遍历到新元素,判断一次,当前元素和左指针指向的最小元素之间的差值是否大于当前记录的最大值,如果大于,则替换当前最大值
class Solution {
    public int maxProfit(int[] prices) {
        if (prices.length == 0) {
            return 0;
        }
        int left = prices[0];
        int max = 0;
        for (int fast = 0; fast < prices.length; fast++) {
            left = Math.min(left, prices[fast]);
            max = Math.max(max, prices[fast] - left);
        }
        return max;
    }
}

最大子序和

暴力又寄了,超时,hhh

class Solution {
    public int maxSubArray(int[] nums) {
        int max = -99999;
        for (int i = 0; i < nums.length; i++) {
            int sum = 0;
            for (int j = i; j < nums.length; j++) {
                sum += nums[j];
                if (sum > max) {
                    max = sum;
                }
            }
        }
        return max;
    }
}

解法1

大佬写的思路,很棒

  1. 定义dp[i]表示数组中下标i为右端点的连续子数组的最大和。
  2. 如果要计算下标i为右端点的连续子数组的最大和,也就是计算dp[i],只需要判断dp[i-1]是大于0还是小于0。如果dp[i-1]大于0,就继续累加,dp[i]=dp[i-1]+num[i]。如果dp[i-1]小于0,我们直接把前面的舍弃,也就是说重新开始计算,否则会越加越小的,直接让dp[i]=num[i]。所以转移公式如下dp[i]=num[i]+max(dp[i-1],0)
  3. 边界条件判断,当i等于0的时候,也就是前1个元素,他能构成的最大和也就是他自己,所以dp[0]=num[0]
class Solution {
    public int maxSubArray(int[] nums) {
        int len = nums.length;
        int[] dp = new int[len];
        dp[0] = nums[0];
        int max = dp[0];
        for (int i = 1; i < len; i++) {
            dp[i] = Math.max(dp[i - 1], 0) + nums[i];
            max = Math.max(max, dp[i]);
        }
        return max;
    }
}

解法2

优化

class Solution {
    public int maxSubArray(int[] nums) {
        int len = nums.length;
        int temp = nums[0];
        int max = temp;
        for (int i = 1; i < len; i++) {
            temp = Math.max(temp, 0) + nums[i];
            max = Math.max(max, temp);
        }
        return max;
    }
}

打家劫舍

思路

这里可以定义一个二维数组dp[length][2],其中dp[i][0]表示第i+1(因为数组下标是从0开始的,所以这里是i+1)家偷了的最大总金额,dp[i][1]表示的是第i+1家没偷的最大总金额。那么我们找出递推公式

  1. dp[i][0]=max(dp[i-1][0],dp[i-1][1])他表示如果第i+1家没偷,那么第i家有没有偷都是可以的,我们取最大值即可。
  2. dp[i][1]=dp[i-1][0]+nums[i]他表示的是如果第i+1家偷了,那么第i家必须没偷,这里nums[i]表示的是第i+1家偷的金额。

解法1

class Solution {
    public int rob(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        int[][] dp = new int[nums.length][2];
        dp[0][0] = 0;
        dp[0][1] = nums[0];
        for (int i = 1; i < nums.length; i++) {
            dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]);
            dp[i][1] = dp[i - 1][0] + nums[i];
        }
        return Math.max(dp[nums.length - 1][0], dp[nums.length - 1][1]);
    }
}

打乱数组

解法1

随机交换

class Solution {
    public int[] nums;
    public Random random = new Random();
    public Solution(int[] nums) {
        this.nums = nums;
    }
    
    public int[] reset() {
        return nums;
    }
    
    public int[] shuffle() {
        if (nums.length == 0) {
            return nums;
        }
        int[] newN = nums.clone();
        for (int i = 1; i < nums.length; i++) {
            int j = random.nextInt(i + 1);
            if (j != i) {
                swap(newN, i, j);
            }
        }
        return newN;
    }

    public void swap(int[] newN, int i, int j) {
        int temp = newN[i];
        newN[i] = newN[j];
        newN[j] = temp;
    }
}

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(nums);
 * int[] param_1 = obj.reset();
 * int[] param_2 = obj.shuffle();
 */

最小栈

解法1

class MinStack {
    private Stack<StackNode> stack = new Stack<>();

    //压栈
    public void push(int x) {
        if (empty()) {
            stack.push(new StackNode(x, x));
        } else {
            stack.push(new StackNode(x, Math.min(x, getMin())));
        }
    }

    //出栈
    public void pop() {
        if (empty())
            throw new IllegalStateException("栈为空……");
        stack.pop();
    }

    public int top() {
        if (empty())
            throw new IllegalStateException("栈为空……");
        return stack.peek().val;
    }

    public int getMin() {
        if (empty())
            throw new IllegalStateException("栈为空……");
        return stack.peek().min;
    }

    //判断栈是否为空
    private boolean empty() {
        return stack.isEmpty();
    }
}

class StackNode {
    public int val;
    public int min;

    public StackNode(int val, int min) {
        this.val = val;
        this.min = min;
    }
}

Fizz Buzz

解法1

简单if

class Solution {
    public List<String> fizzBuzz(int n) {
        List<String> result = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if ((i + 1) % 3 == 0) {
                if ((i + 1) % 5 == 0) {
                    result.add("FizzBuzz");
                    continue;
                }
                result.add("Fizz");
                continue;
            }
            if ((i + 1) % 5 == 0) {
                result.add("Buzz");
                continue;
            }
            result.add((i + 1) + "");
        }
        return result;
    }
}

计数质数

思路

官解思路很妙

计数质数 - 计数质数 - 力扣(LeetCode)

**埃拉托斯特尼筛法(埃氏筛)**官解动图炒鸡好理解

解法1

class Solution {
    public int countPrimes(int n) {
        boolean[] isT = new boolean[n];
        Arrays.fill(isT, true);
        for (int i = 2; i * i < n; i++) {
            if (isT[i]) {
                for (int j = i * i; j < n; j+=i) {
                    isT[j] = false;
                }
            }
        }
        int result = 0;
        for (int i = 2; i < n; i++) {
            if (isT[i]) {
                result++;
            }
        }
        return result;
    }
}

3的幂

解法1

  1. 遍历
class Solution {
    public boolean isPowerOfThree(int n) {
        if (n > 1) {
            while (n % 3 == 0) {
                n /= 3;
            }
        }
        return n == 1;
    }
}

解法2

取最大的3的幂,判断是否为其约数

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

罗马数字转整数

解法1

用时 99.93%,内存98.73%,简单解法 - 罗马数字转整数 - 力扣(LeetCode)

class Solution {
    public int romanToInt(String s) {
        int sum = 0;
        int preNum = getV(s.charAt(0));
        for (int i = 1; i < s.length(); i++) {
            int num = getV(s.charAt(i));
            if (preNum < num) {
                sum -= preNum;
            } else {
                sum += preNum;
            }
            preNum = num;
        }
        sum += preNum;
        return sum;
    }
    public int getV(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;
        }
    }
}

位1的个数

解法1

  1. 位运算
  2. 每一位和1做与运算,等于1,计数自增
public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int count = 0;
        for (int i = 0; i < 32; i++) {
            if (((n >>> i) & 1) == 1) {
                count++;
            }
        }
        return count;
    }
}

汉明距离

解法1

  1. 异或运算
  2. 计算1的个数
class Solution {
    public int hammingDistance(int x, int y) {
        int xor = x ^ y;
        int result = 0;
        while (xor != 0) {
            result += 1;
            xor &= xor - 1;
        }
        return result;
    }
}

解法2

class Solution {
    public int hammingDistance(int x, int y) {
        return Integer.bitCount(x ^ y);
    }
}

颠倒二进制位

解法1

  1. result左移一位空出最后一位
  2. result加n的最后一位
  3. n右移一位挤掉最后一位
  4. 循环32次
  5. 返回
public class Solution {
    // you need treat n as an unsigned value
    public int reverseBits(int n) {
        int result = 0;
        for (int i = 0; i < 32; i++) {
            result <<= 1;
            result |= n & 1;
            n >>= 1;
        }
        return result;
    }
}

杨辉三角

解法1

  1. new一个List,每循环一行add一个List
  2. 单独判断numRows为0、1、2的情况提前返回结果
  3. 从第三行开始循环(line=2),遇到首尾add(1),其他情况add上一行对应的值和上一行对应的值的前一个值的和
class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> result = new ArrayList<>();
        if (numRows == 0) {
            return result;
        }
        result.add(new ArrayList<>());
        result.get(0).add(1);
        if (numRows == 1) {
            return result;
        }
        result.add(new ArrayList<>());
        result.get(1).add(1);
        result.get(1).add(1);
        if (numRows == 2) {
            return result;
        }
        int line = 2;
        while (line < numRows) {
            result.add(new ArrayList<>());
            int count = 0;
            while (count <= line) {
                if (count == 0 || count == line) {
                    result.get(line).add(1);
                    count++;
                    continue;
                }
                result.get(line).add(result.get(line - 1).get(count - 1) + result.get(line - 1).get(count));
                count++;
            }
            line++;
        }
        return result;
    }
}

有效的括号

解法1

  1. 将字符串转为char数组
  2. 遍历数组
  3. 左括号进栈,右括号出栈
  4. 如果碰到不匹配或者该出栈的适合栈为空,返回false
  5. 循环结束后如果栈为空返回true,否则返回false
class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        char[] ccc = s.toCharArray();
        for (int i = 0; i < ccc.length; i++) {
            if (ccc[i] == '(' || ccc[i] == '[' || ccc[i] == '{') {
                stack.push(ccc[i]);
                continue;
            }
            if (ccc[i] == ')') {
                if (stack.isEmpty() || stack.pop() != '(') {
                    return false;
                }
                continue;
            }
            if (ccc[i] == ']') {
                if (stack.isEmpty() || stack.pop() != '[') {
                    return false;
                }
                continue;
            }
            if (ccc[i] == '}') {
                if (stack.isEmpty() || stack.pop() != '{') {
                    return false;
                }
                continue;
            }
        }
        if (stack.isEmpty()) {
            return true;
        }
        return false;
    }
}

缺失数字

解法1

  1. 遍历数组
  2. sum求数组内所有数字的和,he求所有下标值和
  3. 求和之后he自加数组的长度,即为0-n的总和
  4. he-sum即为缺失的数字
class Solution {
    public int missingNumber(int[] nums) {
        int sum = 0;
        int he = 0;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            he += i;
        }
        return he + nums.length - sum;
    }
}