每日刷题记录 (十七)

x33g5p2x  于2022-07-10 转载在 其他  
字(4.3k)|赞(0)|评价(0)|浏览(433)

第一题: 剑指 Offer 33. 二叉搜索树的后序遍历序列

LeetCode: 剑指 Offer 33. 二叉搜索树的后序遍历序列

描述:
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

解题思路:

  1. 因为是后序遍历, 从后往前遍历
  2. 因为最后一个肯定是根节点, 直接入栈.
  • 此时栈不为空, 比较当前遍历到的值是否大于当前栈顶元素.

  • 大于, 继续入栈, 只要比当前栈顶元素大, 就是右树

  • 小于, 就循环去出栈, 并标记当前栈顶元素.这里相当于左树

  • 如果当前进入左树, 标记了栈顶元素, 那么就仅需比较, 当前遍历的值是否大于标记的值, 如果大于, 直接返回false, 这里相当于左子树内容大于根.

  • 遍历结束, 如果都满足要求, 就返回true;

代码实现:

  1. class Solution {
  2. public boolean verifyPostorder(int[] postorder) {
  3. Stack<Integer> stack = new Stack<>();
  4. int root = Integer.MAX_VALUE;
  5. for(int i = postorder.length - 1; i >=0 ;i--) {
  6. // 如果这里的root被标记了(进入左树), 比较是否这个值大于根据节点
  7. if(postorder[i] > root) {
  8. return false;
  9. }
  10. // 只要这里小于栈顶元素, 弹出栈顶元素, 相当于把右树弹出.
  11. while (!stack.isEmpty() && postorder[i] < stack.peek()) {
  12. // 标记新的根节点
  13. root = stack.pop();
  14. }
  15. stack.push(postorder[i]);
  16. }
  17. return true;
  18. }
  19. }

第二题: 剑指 Offer 34. 二叉树中和为某一值的路径

LeetCode: 剑指 Offer 34. 二叉树中和为某一值的路径

描述:
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

解题思路:

  1. 使用回溯解题.
  2. 如果 root 为空 就直接返回
  3. 每次将节点加入list中. 并让 target -= root.val
  4. 如果当前的 target == 0 并且左右子树都为 null, 直接添加到结果集中.
  5. 否则进入左子树, 进入右子树.

代码实现:

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode() {}
  8. * TreeNode(int val) { this.val = val; }
  9. * TreeNode(int val, TreeNode left, TreeNode right) {
  10. * this.val = val;
  11. * this.left = left;
  12. * this.right = right;
  13. * }
  14. * }
  15. */
  16. class Solution {
  17. List<List<Integer>> res = new ArrayList<>();
  18. List<Integer> list = new ArrayList<>();
  19. public List<List<Integer>> pathSum(TreeNode root, int target) {
  20. dfs(root,target);
  21. return res;
  22. }
  23. public void dfs(TreeNode root, int target){
  24. if(root == null) return;
  25. list.add(root.val);
  26. target -= root.val;
  27. if(target == 0 && root.left == null && root.right == null) {
  28. res.add(new ArrayList<>(list));
  29. }else{
  30. dfs(root.left,target);
  31. dfs(root.right,target);
  32. }
  33. list.remove(list.size()-1);
  34. }
  35. }

第三题: 剑指 Offer 35. 复杂链表的复制

LeetCode: 剑指 Offer 35. 复杂链表的复制

描述:
请实现 copyRandomList函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null

解题思路:

  1. 哈希表的方式, 存储节点.
  2. 首先让 cur=head, 遍历链表, 将元素都添加到哈希表中,
  3. 再次让 cur=head, 遍历链表, 通过当前的cur来得到哈希表中存储的节点, 然后将next和random进行链接
  4. 返回哈希表中存储的头节点

代码实现:

  1. class Solution {
  2. public Node copyRandomList(Node head) {
  3. Node cur = head;
  4. Map<Node,Node> map = new HashMap<>();
  5. while(cur != null) {
  6. map.put(cur,new Node(cur.val));
  7. cur = cur.next;
  8. }
  9. cur = head;
  10. while(cur != null) {
  11. // 注意这里的链接方法.
  12. map.get(cur).next = map.get(cur.next);
  13. map.get(cur).random = map.get(cur.random);
  14. cur = cur.next;
  15. }
  16. return map.get(head);
  17. }
  18. }

第四题: 剑指 Offer 38. 字符串的排列

LeetCode: 剑指 Offer 38. 字符串的排列

描述:
输入一个字符串,打印出该字符串中字符的所有排列。

你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。

解题思路:

  1. 这里使用回溯的方法
  2. 使用一个 boolean 数组进行标记来剪枝
  • 该题主要注意的剪枝,

  • 剪枝1: 不能使用重复的元素. (所以对s要进行排序,转成char[]数组来排序, 使用boolean来判断)

  • 剪枝2: 不能重复使用同一个元素. (这里对使用过的进行标记, 如果使用了, 就直接跳过)

代码实现:

  1. class Solution {
  2. List<String> list = new ArrayList<>();
  3. public String[] permutation(String s) {
  4. boolean[] tmp = new boolean[s.length()];
  5. char[] ch = s.toCharArray();
  6. // 注意题目中没有说s是不重复的,所以需要排序
  7. Arrays.sort(ch);
  8. bfs(ch,tmp,new StringBuilder());
  9. String[] ans = new String[list.size()];
  10. for(int i = 0; i < list.size(); i++) {
  11. ans[i] = list.get(i);
  12. }
  13. return ans;
  14. }
  15. public void bfs(char[] ch, boolean[] tmp,StringBuilder sb){
  16. if (sb.length() == ch.length) {
  17. list.add(sb.toString());
  18. return;
  19. }
  20. for(int i = 0; i < ch.length; i++) {
  21. // 剪枝1
  22. if(i > 0 && ch[i] == ch[i-1] && tmp[i-1]){
  23. continue;
  24. }
  25. // 剪枝2
  26. if(tmp[i]){
  27. continue;
  28. }
  29. tmp[i] = true;
  30. sb.append(ch[i]);
  31. bfs(ch,tmp,sb);
  32. sb.deleteCharAt(sb.length()-1);
  33. tmp[i] = false;
  34. }
  35. }
  36. }

第五题: 剑指 Offer 42. 连续子数组的最大和

LeetCode: 剑指 Offer 42. 连续子数组的最大和

描述:
输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

要求时间复杂度为O(n)。

解题思路:

  1. 这里使用动态规划解题
  2. 状态 F(i) : 以当前i下标结尾的最大连续数组的和.
  3. 状态转移方程: F(i) = Math.max( nums[i], F(i-1)+nums[i])
  4. 初始状态: F(0) = nums[0]
  5. 返回结果: 返回 Math.max(F(i))

代码实现:

  1. class Solution {
  2. public int maxSubArray(int[] nums) {
  3. int[] dp = new int[nums.length];
  4. dp[0] = nums[0];
  5. int max = nums[0];
  6. for(int i = 1; i < nums.length; i++) {
  7. dp[i] = Math.max(nums[i],dp[i-1]+nums[i]);
  8. max = Math.max(dp[i],max);
  9. }
  10. return max;
  11. }
  12. }

第六题: 剑指 Offer 44. 数字序列中某一位的数字

LeetCode: 剑指 Offer 44. 数字序列中某一位的数字

描述:
数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。

请写一个函数,求任意第n位对应的数字。

解题思路:

  1. 这题是找规律的题
范围位数数据量所有的数位量
1 ~ 9199
10 ~ 99290180
100 ~ 99939002700
start ~ start*10-1digit9 * start9 * digit * start
  1. 按照规律, 首先可以先定位到该数在哪一个范围
  2. 再根据start求出当前的值. start +( n - 1 ) / digit
  3. 找到这个值, 再根据 (n-1)%digit, 得到这个值的第这个位.

代码实现:

  1. class Solution {
  2. public int findNthDigit(int n) {
  3. int digit = 1;
  4. // 因为范围过大, 还涉及到乘法, 要考虑溢出使用long
  5. long count = 9;
  6. long start = 1;
  7. while(n > count) {
  8. n -= count;
  9. digit++;
  10. start *= 10;
  11. count = digit * start * 9;
  12. }
  13. // 得到原来的数
  14. long num = start + (n - 1) / digit;
  15. String ans = num+"";
  16. // 根据这个数转成字符串, 来得到该位下的值.
  17. return ans.charAt((n - 1) % digit) - '0';
  18. }
  19. }

相关文章