万隆的笔记 万隆的笔记
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
  • 数据结构与算法

  • 设计模式

  • 编程方法论

  • 分布式设计与微服务理论

  • Leetcode

    • Question :1 - 100
      • Q1:两数之和
      • Q7*:整数反转Ω
      • Q8*:字符串转换整数 (atoi)
      • Q9:回文数
      • Q13:罗马数字转整数
      • Q14:最长公共前缀
      • Q19*:删除链表的倒数第 N 个结点
      • Q20:有效的括号
      • Q21:合并两个有序链表
      • Q26:删除有序数组中的重复项
      • Q28:实现strStr()
      • Q36*:有效的数独
      • Q38*:外观数列
      • Q48*:旋转图像
      • Q53:最大子数组和
      • Q66:加一
      • Q70*:爬楼梯
      • Q94:二叉树的中序遍历
    • Question :101 - 200
    • Question :201 - 300
    • Question :301 - 400
  • 程序员内功
  • Leetcode
2022-05-08
目录

Question :1 - 100

# Question :1 - 100

记录我的LeetCode答题记录。说明:

  • 编程语言:Java
  • 每道题只记录自己做出来的“最优解”(耗时最少)。
  • 每道题其他题解可能记录在本人的的项目- leetCode (opens new window),或去官方看大家的提交记录。

# Q1:两数之和 (opens new window)

public int[] twoSum(int[] nums, int target) {
		int[] result = new int[2];
		Map<Integer, Integer> map = new HashMap<>();
		for (int x = 0, len = nums.length; x < len; ++x) {
			if (map.containsKey(target-nums[x])){
				result[0] = x;
				result[1] = map.get(target-nums[x]);
				return result;
			}
			map.put(nums[x], x);
		}
		return result;
}

# Q7*:整数反转Ω (opens new window)

public int reverse(int x) {
		int r = 0 , temp;
		while (x != 0){
			temp = r * 10 + x % 10;
			if (temp / 10 != r){
				return 0;
			}
			r = temp;
			x /= 10;
		}
		return r;
}

# Q8*:字符串转换整数 (atoi) (opens new window)

public int myAtoi(String s) {
  if (s == null || s.length() == 0) {
    return 0;
  }

  char[] chars = s.toCharArray();
  int index = 0, result = 0, sign = 1;
  boolean hasNumber = false;
  while (index < chars.length){
    char aChar = chars[index];
    if (aChar >= '0' && aChar <= '9'){
      int temp = result * 10 + (aChar - '0');
      if (temp / 10 != result) {
        return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
      }
      result = temp;
      hasNumber = true;
    } else if (aChar == ' ' || aChar == '-' || aChar == '+'){
      // 数字中间出现特殊字符或+、-连续出现
      if (hasNumber || (aChar != ' '
                        && index != s.length() - 1
                        && (chars[index + 1] < '0' || chars[index + 1] > '9'))){
        break;
      }
      if (aChar != ' '){
        sign = aChar == '-' ? -1 : 1;
      }
    }else {
      break;
    }
    index++;
  }

  return result * sign;
}

# Q9:回文数 (opens new window)

public boolean isPalindrome(int x) {
    if (x < 0 || (x % 10 == 0 && x != 0)){
        return false;
    }
    int revertedNumber = 0;
    while (x > revertedNumber) {
        revertedNumber = revertedNumber * 10 + x % 10;
        x /= 10;
    }
    return x == revertedNumber || x == revertedNumber / 10;
}

# Q13:罗马数字转整数 (opens new window)

public int romanToInt(String s) {
  int result = 0;
  char[] chars = s.toCharArray();
  for (int i = 0, n = chars.length; i < n; i++) {
    int current = romanValueOf(chars[i]);

    if(i < n - 1 && romanValueOf(chars[i]) < romanValueOf(chars[i + 1])) {
      result -= current;
    }else {
      result += current;
    }

  }
  return result;
}

private Integer romanValueOf(Character roman) {
  switch (roman) {
    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;
  }
}

# Q14:最长公共前缀 (opens new window)

public String longestCommonPrefix(String[] strs) {
  if( strs.length == 0){
    return "";
  }else{
    String commonPre = strs[0];
    for(String str : strs){
      while(!str.startsWith(commonPre)){
        if (commonPre.length() == 1){
          return "";
        }
        commonPre = commonPre.substring(0, commonPre.length() - 1);
      }
    }
    return commonPre;
  }
}

# Q19*:删除链表的倒数第 N 个结点 (opens new window)

public ListNode removeNthFromEnd(ListNode head, int n) {
  ListNode dummy = new ListNode(0, head);
  ListNode first = head, second = dummy;
  for (int i = 0; i < n; ++i) {
    first = first.next;
  }
  while (first != null) {
    first = first.next;
    second = second.next;
  }
  second.next = second.next.next;
  return dummy.next;
}

# Q20:有效的括号 (opens new window)

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<>();
    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();
}

# Q21:合并两个有序链表 (opens new window)

public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
    if (list1 == null){
        return list2;
    }else if (list2 == null){
        return list1;
    }else if (list1.val <= list2.val){
        list1.next = mergeTwoLists(list1.next, list2);
        return list1;
    }else {
        list2.next = mergeTwoLists(list1, list2.next);
        return list2;
    }
}

# Q26:删除有序数组中的重复项 (opens new window)

public int removeDuplicates(int[] nums) {
  int newLen = 0;
  for(int x = 1, len = nums.length; x < len; ++x) {
    if(nums[newLen] != nums[x]) {
      ++newLen;
      nums[newLen] = nums[x];
    }
  }
  return newLen + 1;
}

# Q28:实现strStr() (opens new window)

题目本质考的是字符串匹配问题,题目归类为简单,可直接使用String的indexOf()。这里我使用了KMP算法实现,比JDK 8的indexOf()效率高不少。

KMP算法,推荐博客:

  • https://www.cnblogs.com/yjiyjige/p/3263858.html
  • https://www.cnblogs.com/dusf/p/kmp.html(基于上一篇博客补充修改)
public int strStr(String haystack, String needle){
  
  char[] tsChars = haystack.toCharArray();
  char[] psChars = needle.toCharArray();

  // 主串、模式串的index
  int i = 0, j = 0;
  // KMP核心算法
  int[] next = getNext(needle);

  while (i < haystack.length() && j < needle.length()){
    // 当j为-1时,要移动的是i,j也要归0
    if (j == -1 || tsChars[i] == psChars[j]) {
      i++;
      j++;
    }
    // j回到指定位置,同时i不需要回溯
    else{
      j = next[j];
    }
  }

  return j == needle.length() ? i-j : -1;
}

/**
* 模next[j] = k,表示当T[i] != P[j]时,模式串j指针的下一个位置。
*/
private int[] getNext(String ps) {

  if (ps.length() == 0){
    return new int[0];
  }

  char[] p = ps.toCharArray();
  int[] next = new int[p.length];

  next[0] = -1;

  int j = 0, k = -1;

  while (j < p.length - 1) {

    if (k == -1 || p[j] == p[k]) {
      // 优化next[++j] = ++k; 跳过t[j] == t[next[j]]的情况,
      if (p[++j] == p[++k]) {
        next[j] = next[k];
      } else {
        next[j] = k;
      }
    } else {
      k = next[k];
    }
  
  }

  return next;
}

# Q36*:有效的数独 (opens new window)

public boolean isValidSudoku(char[][] board) {
  int[][] rows = new int[9][9];
  int[][] columns = new int[9][9];
  int[][][] subBoxes = new int[3][3][9];
  for (int i = 0; i < 9; ++i) {
    for (int j = 0; j < 9; ++j) {
      char c = board[i][j];
      if (c != '.') {
        int index = c - '0' - 1;
        rows[i][index]++;
        columns[j][index]++;
        subBoxes[i/3][j/3][index]++;
        if (rows[i][index] > 1 || columns[j][index] > 1 || subBoxes[i / 3][j / 3][index] > 1) {
          return false;
        }
      }
    }
  }
  return true;
}

# Q38*:外观数列 (opens new window)

public String countAndSay(int n) {
  String say = "1";
  while(--n > 0) {
    int num = 1;
    char[] chars = say.toCharArray();
    StringBuilder countSay = new StringBuilder();
    // 索引改为从1开始
    for(int i = 1; i < say.length(); ++i) {
      if(chars[i] == chars[i-1]) {
        ++num;
      }else {
        countSay.append(num).append(chars[i-1]);
        num = 1;
      }
    }
    // 此处转换为字符串,需要添加最后一个字符的统计
    say = countSay.append(num).append(chars[say.length()-1]).toString();
  }
  return say;
}

# Q48*:旋转图像 (opens new window)

/**
 * 原地旋转,四项循环具体推导过程可参考官方解答。
 * 还有其他原地旋转的解法如下,源码可参见仓库。
 * 1. 先以对角线(右斜)为轴翻转,再以x轴为轴翻转得到结果。
 * 2. 对矩阵进行转置,即行变成列(以对角线(左斜)为轴翻转),再以y轴为轴翻转得到结果。
 */
public void rotate(int[][] matrix) {
	int n = matrix.length;
	for (int i = 0; i < n / 2 ; ++i) {
		for (int j = 0; j < (n + 1) / 2; ++j) {
			// 四项循环
			int temp = matrix[i][j];
			matrix[i][j] = matrix[n - j - 1][i];
			matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1];
			matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1];
			matrix[j][n - i - 1] = temp;
		}
	}
}

# Q53:最大子数组和 (opens new window)

public int maxSubArray2(int[] nums) {
    int res = nums[0], sum = 0;
    for (int num : nums) {
        sum = Math.max(num, sum + num);
        res = Math.max(res, sum);
    }
    return res;
}

# Q66:加一 (opens new window)

public int[] plusOne(int[] digits){
   for (int i = digits.length - 1; i >= 0; --i){
      if (digits[i] != 9){
         digits[i]++;
         return digits;
      }
      digits[i] = 0;
   }
   int[] result = new int[digits.length + 1];
   result[0] = 1;
   return result;
}

# Q70*:爬楼梯 (opens new window)

/**
* m4(0ms, 45tc): 动态规划,滚动数组
* Tn = O(n),Sn = O(1)
*/
public int climbStairs4(int n) {
  int first = 0, second = 0, third = 1;
  for (int i = 1; i <= n; i++) {
    first = second;
    second = third;
    third = first + second;
  }
  return third;
}

/**
* m6(0ms, 45tc): 通项公式, Binet's Formula
* Tn = O(logn),Sn = O(1)
*/
public int climbStairs6(int n) {
  double sqrt5 = Math.sqrt(5);
  double result = (Math.pow((1 + sqrt5)/2, n + 1) - Math.pow((1 - sqrt5)/2, n + 1)) / sqrt5;
  return (int)result;
}

# Q94:二叉树的中序遍历 (opens new window)

/**
* 递归版
*/
public List<Integer> inorderTraversal(TreeNode root) {
  List<Integer> list = new ArrayList<>();
  inorder(root, list);
  return list;
}

private void inorder(TreeNode root, List<Integer> list) {
  if (root == null) {
    return;
  }

  inorder(root.left, list);
  list.add(root.val);
  inorder(root.right, list);
}
上次更新: 5/21/2023, 11:34:33 PM
Question :101 - 200

Question :101 - 200→

最近更新
01
2025
01-15
02
Elasticsearch面试题
07-17
03
Elasticsearch进阶
07-16
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式