202. 快乐数

该题的难点主要在:如何检测出会发生循环。
如果检测出会发生循环,那么永远不可能变为1,则返回 false。
LC 201 ~ 300 - 图1
方法一:利用「哈希表可以快速判断元素是否在集合中」的特点。
把出现过的值加入到集合中,如果当前值存在集合中,那么就意味着会发生循环,返回 false。
方法二:判断链表是否有环的问题,弗洛伊德循环查找算法
方法三:数学法
所有的非快乐数只存在一个循环,也就是:4 ->16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 -> 4
不存在其他循环,只要出现这几个数中的其中一个,就可以判定一定会发生循环,返回 false。

206. 反转链表

反转的步骤:

  • 记录要反转的节点为 curr,记录 curr 的前一个节点为 prev,记录 curr 的后一个节点为 next
  • 改变 curr 的指向,即 curr.next = prev
  • prev 前进一个节点,即 prev = curr
  • curr 前进一个节点,即 curr = next
  • next 前进一个节点,即 next = curr.next(即上面的记录 curr 的后一个节点为 next,循环的起始)
  • 循环往复,直到 curr 为 null,prev 即为反转链表的头节点

    1. class Solution {
    2. public ListNode reverseList(ListNode head) {
    3. // curr 的前一个节点
    4. ListNode prev = null;
    5. ListNode curr = head;
    6. // curr 的后一个节点
    7. ListNode next = null;
    8. while (curr != null) {
    9. // next 前进
    10. next = curr.next;
    11. // 反转
    12. curr.next = prev;
    13. // prev 前进
    14. prev = curr;
    15. // curr 前进
    16. curr = next;
    17. }
    18. return prev;
    19. }
    20. }
    1. class Solution {
    2. public ListNode reverseList(ListNode head) {
    3. ListNode node = recursion(null, head);
    4. return node;
    5. }
    6. private ListNode recursion(ListNode prev, ListNode curr) {
    7. if (curr == null) {
    8. return prev;
    9. }
    10. ListNode node = recursion(curr, curr.next);
    11. curr.next = prev;
    12. return node;
    13. }
    14. }
    1. class Solution {
    2. public ListNode reverseList(ListNode head) {
    3. ListNode node = recursion(head);
    4. return node;
    5. }
    6. private ListNode recursion(ListNode node) {
    7. if ( node == null || node.next == null) {
    8. return node;
    9. }
    10. ListNode node1 = recursion(node.next);
    11. node.next.next = node;
    12. node.next = null;
    13. return node1;
    14. }
    15. }

    209. 长度最小的子数组

    1. class Solution {
    2. public int minSubArrayLen(int target, int[] nums) {
    3. {
    4. /*
    5. 时间复杂度:O(n)
    6. */
    7. }
    8. // l、r 是窗口的左右边界
    9. int l = 0;
    10. int r = 0;
    11. // sum 是窗口内 nums 的总和
    12. int sum = 0;
    13. int result = Integer.MAX_VALUE;
    14. while (r < nums.length) {
    15. sum += nums[r];
    16. while (sum >= target && l <= r) {
    17. result = Math.min(result, r - l + 1);
    18. sum -= nums[l];
    19. l++;
    20. }
    21. r++;
    22. }
    23. if (result == Integer.MAX_VALUE) {
    24. return 0;
    25. } else {
    26. return result;
    27. }
    28. }
    29. }

216. 组合总和 III

  1. class Solution {
  2. List<List<Integer>> results = new ArrayList<>();
  3. List<Integer> result = new ArrayList<>();
  4. int k;
  5. int n;
  6. public List<List<Integer>> combinationSum3(int k, int n) {
  7. this.k = k;
  8. this.n = n;
  9. backtracking(1, 0);
  10. return results;
  11. }
  12. // s 代表集合的起始元素 [s...9]
  13. public void backtracking(int s, int sum) {
  14. if (result.size() == k) {
  15. if (sum == n) {
  16. results.add(new ArrayList<>(result));
  17. }
  18. return;
  19. }
  20. for (int i = s; i <= 9; i++) {
  21. result.add(i);
  22. backtracking(i + 1, sum + i);
  23. result.remove(result.size() - 1);
  24. }
  25. }
  26. }
  1. class Solution {
  2. List<List<Integer>> results = new ArrayList<>();
  3. List<Integer> result = new ArrayList<>();
  4. int k;
  5. int n;
  6. public List<List<Integer>> combinationSum3(int k, int n) {
  7. this.k = k;
  8. this.n = n;
  9. backtracking(1, 0);
  10. return results;
  11. }
  12. // s 代表集合的起始元素 [s...9]
  13. public void backtracking(int s, int sum) {
  14. if (result.size() == k) {
  15. if (sum == n) {
  16. results.add(new ArrayList<>(result));
  17. }
  18. return;
  19. }
  20. // 剪枝:数量不足的情况 和 相加之和必定不能满足条件的情况(和太大、和太小)
  21. for (int i = s; i <= 9 && (result.size() + 10 - i) >= k && (sum + (k - result.size()) * i) <= n && (sum + (k - result.size()) * 9) >= n; i++) {
  22. result.add(i);
  23. backtracking(i + 1, sum + i);
  24. result.remove(result.size() - 1);
  25. }
  26. }
  27. }

有效的字母异位词

有思路,不写了
方法一:先对字符排序,再逐个比较
方法二:哈希表