
剑指offer
傅里叶不想变换_
这个作者很懒,什么都没留下…
展开
-
剑指 Offer 68 - II. 二叉树的最近公共祖先
思路:通过递归对二叉树进行后序遍历,当遇到节点 p 或 q 时返回。从底至顶回溯,当节点 p, q 在节点 root的异侧时,节点 root 即为最近公共祖先,则向上返回 root四种情况:class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if(root == null) return null; // 如果p和q中有等.原创 2021-06-29 09:48:09 · 91 阅读 · 0 评论 -
剑指 Offer 66. 构建乘积数组
思路:暴力法,乘积 res[i] = sum / a[i] 但是题目说不能使用除法,故不能使用暴力法。要求除了这个数的乘积,即这个数的左边×右边,左右各维护一个数组,结果就是左边×右边。left[i]表示第i位之前的乘积,right[i]表示第i位之后的乘积class Solution { public int[] constructArr(int[] a) { if (a == null || a.length == 0) return a; int le.原创 2021-03-06 14:46:08 · 73 阅读 · 0 评论 -
剑指 Offer 59 - I. 滑动窗口的最大值
思路:结果集的大小应该为 res = new int[n - k + 1],边界条件有 n == 0, k == 1class Solution { public int[] maxSlidingWindow(int[] nums, int k) { if(nums.length==0) return new int[0]; if(k == 1) return nums; int n = nums.length; int[] re.原创 2021-03-04 16:59:10 · 248 阅读 · 2 评论 -
剑指 Offer 59 - II. 队列的最大值
思路:使用一个普通队列,一个辅助队列(单调非递减队列),辅助队列 deque的队首元素就是队列的最大值。class MaxQueue { Deque<Integer> deque; Deque<Integer> queue; public MaxQueue() { deque = new LinkedList<>(); queue = new LinkedList<>(); } // 如果辅.原创 2021-03-04 15:45:27 · 99 阅读 · 3 评论 -
剑指 Offer 20. 表示数值的字符串
思路:遍历字符串,分四种情况,. 数字 e/E -/+条件: 1 .之前不能出现.或者e` 2 e之前不能出现e,必须出现数 3 +-出现在0位置或者e/E的后面第一个位置才是合法的class Solution { public boolean isNumber(String s) { if(s == null || s.length() == 0){ return false; } //标记是否遇到相应情况.原创 2021-03-04 10:47:50 · 74 阅读 · 1 评论 -
剑指 Offer 13. 机器人的运动范围
思路:DFS或者BFSDFS版本class Solution { public int movingCount(int m, int n, int k) { boolean[][] visited = new boolean[m][n]; return dfs(m, n, k, visited, 0, 0); } public int dfs(int m, int n, int k, boolean[][] visited, int x, .原创 2021-03-02 19:26:40 · 111 阅读 · 0 评论 -
剑指 Offer 56 - II. 数组中数字出现的次数 II
思路:将所有的数字都用二进制表示,对于出现三次的数字,各个 二进制位 出现的次数都是 3 的倍数。因此,统计所有数字的各二进制位中 1 的出现次数,并对 3 求余,结果则为只出现一次的数字。class Solution { public static int singleNumber2(int[] nums) { int[] bitArr = new int[32]; for (int i = 0; i < nums.length; i++) { .原创 2021-02-01 15:05:58 · 104 阅读 · 0 评论 -
剑指 Offer 56 - I. 数组中数字出现的次数
思路:异或,我们可以把所有数字分成两组,使得: 1.两个只出现一次的数字在不同的组中; 2.相同的数字会被分到相同的组中。class Solution { public int[] singleNumbers(int[] nums) { int sum = 0; // 将所有数字异或 for (int num : nums) { sum ^= num; } // 找到二进制中第一.原创 2021-02-01 11:56:46 · 79 阅读 · 0 评论 -
剑指 Offer 58 - I. 翻转单词顺序
思路:1.库函数这么写没有考虑到中间有多个空格的情况,"a good example(中间三个空格)"会分割成 a good 空格 空格 example,此时逆序会输出多余空格 example good a (中间三个空格) 2.双指针,从后往前开始遍历,记录单词左右索引边界 i , j ;class Solution { public static String reverseWords(String s) { String[] strings = s.trim.原创 2021-01-31 21:15:36 · 93 阅读 · 1 评论 -
剑指 Offer 57. 和为s的两个数字
思路:注意递增序列,看到递增序列首先一般联想到双指针或者二分法。class Solution { public int[] twoSum(int[] nums, int target) { int l = 0, r = nums.length - 1; while (l < r){ if (nums[l] + nums[r] == target){ return new int[]{nums[l], n.原创 2021-01-31 20:33:45 · 76 阅读 · 0 评论 -
剑指 Offer 57 - II. 和为s的连续正数序列
思路:双指针class Solution { public int[][] findContinuousSequence(int target) { List<int[]> res = new ArrayList<>(); for (int l = 1, r = 2; l < r;) { int sum = (l + r) * (r - l + 1) / 2; if (sum == ta.原创 2021-01-31 20:28:33 · 79 阅读 · 0 评论 -
剑指 Offer 49. 丑数
思路:每个丑数都是由前一个丑数 x2或x3或x5而来,那么就会nums2 = {1*2, 2*2, 3*2, 4*2, 5*2, 6*2, 8*2...}nums3 = {1*3, 2*3, 3*3, 4*3, 5*3, 6*3, 8*3...}nums5 = {1*5, 2*5, 3*5, 4*5, 5*5, 6*5, 8*5...}可以得到三个这样的数组,我们维护三个指针,每次都在三个数组中取出一个最小的。核心思想:当一个丑数已经被* 2 * 3 * 5后,对于生成丑数已经没有用了,所以此.原创 2021-01-30 21:10:35 · 85 阅读 · 0 评论 -
剑指 Offer 50. 第一个只出现一次的字符
思路:哈希表存储 字符 到 出现次数的映射即可class Solution { public char firstUniqChar(String s) { char[] chars = s.toCharArray(); Map<Character, Integer> dic = new HashMap<>(); for (char c : chars) { dic.put(c, dic.getOrDe.原创 2021-01-30 20:22:18 · 72 阅读 · 0 评论 -
剑指 Offer 07. 重建二叉树
思路:在前序序列中,根结点是第一个元素。在中序序列中找到它就可以将左右子树区分开。然后就可以重建二叉树分析:左子树的结点个数numLeft = k - inL左子树中序序列[inL, k - 1],后序序列 [postL, postL + numLeft - 1]。右子树中序序列[k + 1, inR],后序序列 [postL + numLeft, postR - 1]。后记:类似还有已知道中序序列和先序序列,思路很相似。仍然是左子树的结点个数numLeft = k - inL左子树中序序列.原创 2021-01-28 21:51:14 · 100 阅读 · 0 评论 -
剑指 Offer 68 - I. 二叉搜索树的最近公共祖先
思路1:分别记录根节点到p和q的路径,两条路径中最后一个相同的节点就是共同祖先思路2:若 root 是 p,q 的 最近公共祖先 ,则只可能为以下情况之一: 1.p 和 q 在 root 的子树中,且分列 root 的 异侧(即分别在左、右子树中) 2.p=root,且 q 在 root 的左或右子树中 3.q=root,且 p 在 root 的左或右子树中public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, Tre.原创 2021-01-28 11:00:11 · 94 阅读 · 0 评论 -
剑指 Offer 28. 对称的二叉树
思路:从顶至底递归,判断每对节点是否对称,从而判断树是否为对称二叉树。class Solution { public boolean isSymmetric(TreeNode root) { if (root == null) return true; return helper(root.left, root.right); } boolean helper(TreeNode L, TreeNode R){ // 如果左右同.原创 2021-01-27 19:43:57 · 86 阅读 · 0 评论 -
剑指 Offer 55 - II. 平衡二叉树
思路:写一个函数treeDepth来返回树的高度class Solution { public boolean isBalanced(TreeNode root) { if (root == null) return true; int leftTreeDepth = treeDepth(root.left); int rightTreeDepth = treeDepth(root.right); if (Math.abs(ri.原创 2021-01-27 15:50:24 · 141 阅读 · 2 评论 -
剑指 Offer 54. 二叉搜索树的第k大节点
思路:二叉搜索树的中序遍历是递增序列,将中序遍历的结果保存下来,返回中序遍历的倒数第k个元素即可。二叉搜索树第 k 大的节点可转化为求 此树的中序遍历的倒数第 k 个节点class Solution { public int kthLargest(TreeNode root, int k) { List<Integer> res = new ArrayList<>(); inorder(root, res); //.原创 2021-01-27 12:31:55 · 151 阅读 · 0 评论 -
剑指 Offer 48. 最长不含重复字符的子字符串
思路:双指针+滑动窗口,使用哈希表记录每个字母最后一次出现的位置。 public int lengthOfLongestSubstring2(String s) { Map<Character, Integer> map = new HashMap<>(); int left = 0, right = 0, res = 0; for (int i = 0; i < s.length(); i++) { .原创 2021-01-26 22:54:59 · 85 阅读 · 0 评论 -
剑指 Offer 47. 礼物的最大价值
思路:与leetcode120题——最短路径和相似,动态规划,使用dp[i][j] 表示到达位置(i,j)时礼物的最大价值,注意边界条件。初始条件:dp[0][0] = grid[0][0]转移方程:返回值:dp[m-1][n-1]class Solution { public int maxValue(int[][] grid) { if (grid.length == 0 || grid[0].length == 0){ return 0; .原创 2021-01-25 10:32:48 · 126 阅读 · 0 评论 -
139. 单词拆分
思路:定义 dp[i] 表示字符串 s 前 i 个字符组成的字符串 s[0…i-1] 是否能被空格拆分成若干个字典中出现的单词。public class Solution { public boolean wordBreak(String s, List<String> wordDict) { Set<String> wordDictSet = new HashSet(wordDict); boolean[] dp = new boole.原创 2021-01-24 21:36:39 · 91 阅读 · 0 评论 -
剑指 Offer 42. 连续子数组的最大和
思路: 1.暴力法 2.动态规划:dp[i] 代表以元素 nums[i] 为结尾的连续子数组最大和,遍历dp找到最大值即可。 当 dp[i - 1] ≤0 时:执行 dp[i] = nums[i]; 当 dp[i−1]>0 时:执行 dp[i] = dp[i-1] + nums[i]; public int maxSubArray(int[] nums) { if (nums.length == 1) return nums[0]; .原创 2021-01-24 19:33:00 · 92 阅读 · 0 评论 -
347. 前 K 个高频元素
思路:使用最小堆维护一个元素数目为 k 的最小堆每次都将新的元素与堆顶元素(堆中频率最小的元素)进行比较如果新的元素的频率比堆顶端的元素大,则弹出堆顶端的元素,将新的元素添加进堆中最终,堆中的 k 个元素即为前 k 个高频元素注意:1.避免使用大根堆,因为需要把所有元素压入堆,复杂度是 nlogn,而且还浪费内存。如果是海量元素,那就挂了 2.对于 topk 问题:最大堆求topk小,最小堆求 topk 大class Solution { public int[] topKF.原创 2021-01-24 17:35:10 · 180 阅读 · 0 评论 -
剑指 Offer 40. 最小的k个数
思路:1.直接排序后取前k个值 2.用一个大根堆实时维护数组的前 k 小值。首先将前 k 个数插入大根堆中,随后从第 k+1个数开始遍历,如果当前遍历到的数比大根堆的堆顶的数要小,就把堆顶的数弹出,再插入当前遍历到的数。最后将大根堆里的数存入数组返回即可,注意,java默认是小根堆,实现大根堆需要重写一下比较器。 3.快排(待完善) public int[] getLeastNumbers(int[] arr, int k) { if (arr.length == 0.原创 2021-01-24 17:10:11 · 111 阅读 · 0 评论 -
剑指 Offer 38. 字符串的排列
思路:递归+回溯public class Solution { public String[] permutation(String s) { int len = s.length(); if (len == 0) return new String[0]; // 转换成字符数组是常见的做法 char[] charArray = s.toCharArray(); // 排序是为了去重方便 Arra.原创 2021-01-24 15:07:03 · 97 阅读 · 0 评论 -
剑指 Offer 15. 二进制中1的个数
思路:位运算注意 >> 和 >>>的区别: >>表示右移,如果该数为正,则高位补0,若为负数,则高位补1; >>>表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0。public class Solution { // you need to treat n as an unsigned value public int hammingWeight(int n) { .原创 2021-01-23 13:27:48 · 75 阅读 · 0 评论 -
剑指 Offer 39. 数组中出现次数超过一半的数字
思路: 1.哈希表 2.排序,排序完后出现次数最多的数一定在中间位置 3.摩尔投票, 将出现次数超过一半的数字记为众数,若记众数的票数为 +1 ,非众数的票数为 -1 ,则一定有所有数字的票数和 >0 。 public static int majorityElement(int[] nums) { Map<Integer, Integer> map = new HashMap<>(); for (int num : num.原创 2021-01-23 10:07:30 · 94 阅读 · 0 评论 -
剑指 Offer 09. 用两个栈实现队列
思路:栈是先进后出,队列是先进先出,故用两个栈来模拟队列。如图,要添加元素,直接在A中添加即可,但是要删除栈底元素(即模拟队列),直接使用栈A无法删除,故使用辅助栈B将A中的元素逆序存放,然后弹出B的栈顶即可。//A 用于加入队尾操作,栈 B 用于将元素倒序class CQueue { LinkedList<Integer> A, B; public CQueue() { A = new LinkedList<Integer>(); .原创 2021-01-22 20:10:40 · 150 阅读 · 0 评论 -
剑指 Offer 34. 二叉树中和为某一值的路径
思路: 深度优先+回溯dfs(root, sum)函数: 终止条件:结点root为空,直接返回 递推工作: 1.加入当前结点的值root.val,并且更新sum-=root.val 2.如果当前结点为叶子结点且路径和==sum,则将此路径path加入resclass Solution { List<List<Integer>> res = new LinkedList<>(); LinkedList<Integer> pa.原创 2021-01-22 10:33:42 · 89 阅读 · 0 评论 -
剑指 Offer 36. 二叉搜索树与双向链表
思路:二叉树的中序遍历是递增的,因此会想到中序遍历。class Solution { Node pre, head; public Node treeToDoublyList(Node root) { if(root == null) return null; inorder(root); head.left = pre; pre.right = head; return head; } ..原创 2021-01-21 14:38:56 · 97 阅读 · 0 评论 -
剑指 Offer 55 - I. 二叉树的深度
思路:递归,DFS或者BFS层次遍历递归版本class Solution { public int maxDepth(TreeNode root) { if (root == null) { return 0; } else { // 左子树高度 int leftHeight = maxDepth(root.left); // 右子树高度 int r.原创 2021-01-21 10:52:03 · 138 阅读 · 6 评论 -
剑指 Offer 35. 复杂链表的复制
思路: 1.构建 原链表节点 和 新链表对应节点 的键值对映射关系 2.复制拼接一份链表,然后再拆分成两个链表。class Solution { public Node copyRandomList(Node head) { if(head == null) return null; Node cur = head; Map<Node, Node> map = new HashMap<>(); //.原创 2021-01-17 10:57:30 · 1214 阅读 · 0 评论 -
剑指 Offer 20. 表示数值的字符串
class Solution { public static boolean isNumber(String s) { if(s == null || s.length() == 0){ return false; } //标记是否遇到相应情况 boolean numSeen = false; boolean dotSeen = false; boolean eSeen = fa.原创 2021-01-16 15:52:58 · 79 阅读 · 0 评论 -
剑指 Offer 32 - III. 从上到下打印二叉树 III
思路: BFS,定义一个List<List<Integer>> ans,定义临时的LinkedList<Integer> tmp,遍历一层就把tmp加入到 ans中。注意: 奇偶层时,tmp加入顺序不同,可以用layer表示层数,也可以用布尔变量 flag记录,或者可以用 res.size()记录。如果res.size() % 2 == 1则表示奇数层。class Solution { public List<List<Integer&g.原创 2021-01-15 19:19:50 · 115 阅读 · 0 评论 -
剑指 Offer 52. 两个链表的第一个公共节点
思路: 1.统计两个链表长度 lenA 和 lenB ,让长度长的链表先走 abs(lenB - lenA) 步,然后两个链表一起向前走,两个结点相等时退出循环。 2.A链表总长度为LA + C,B链表总长度为LB + C,A链表走完后指向B的头结点,再指向headB,走LB长度,此时A走过的总长度为 LA + C + LB,同理, B 走过的总长度为 LB + C +LA,此时就会相遇。注意点:尽量不要改变头结点head统计长度版本public class Solution { p.原创 2021-01-11 11:45:32 · 115 阅读 · 4 评论 -
剑指 Offer 24. 反转链表
定义两个指针: prev 和 curr, prev 在前 curr 在后。ListNode = null, ListNode curr = head; 每次让 curr 的 next 指向 prev ,实现一次局部反转curr.next = prev; 局部反转完成之后, prev 和 curr 同时往前移动一个位置prev = cur;cur = nextNode; 循环上述过程,直至 prev 到达链表尾部注意:要先移动prev再移动curr,即prev = cur;cur = ne.原创 2021-01-11 10:40:15 · 149 阅读 · 0 评论 -
剑指 Offer 06. 从尾到头打印链表
思路: 1.栈是先进后出,可以不断压栈,最后依次弹出即可。注意for循环中不能用stack.size(),因为栈在弹出过程中size会变化。 2.递归 递推阶段: 每次传入 head.next ,以 head == null(即走过链表尾部节点)为递归终止条件,此时直接返回。 回溯阶段: 层层回溯时,将当前节点值加入列表,即tmp.add(head.val)。最终,将列表 tmp 转化为数组 res ,并返回即可。以链表1 -> 2 为例,画的递归示意图。public.原创 2021-01-11 09:36:28 · 70 阅读 · 0 评论 -
剑指 Offer 22. 链表中倒数第k个节点
思路: 1.先遍历一次获得链表长度n,然后从头开始走n - k步即可 2.快慢指针,先让快指针走k步,然后两个指针同时前进,当快指针遍历完链表时,返回 slow 即可。注意循环条件,如果是fast != null,应该走k步,如果是fast.next != null,应该走k - 1步。思路1class Solution { public ListNode getKthFromEnd(ListNode head, int k) { if(head == nul.原创 2021-01-11 00:57:36 · 89 阅读 · 0 评论 -
剑指 Offer 26. 树的子结构
class Solution { public static boolean isSubStructure(TreeNode A, TreeNode B) { if (A == null || B == null) return false; //先从根节点判断B是不是A的子结构,如果不是在分别从左右两个子树判断, //B不光有可能是A的子结构,也有可能是A左子树的子结构或者右子树的子结构,只要有一个成立就返回true ..原创 2021-01-10 20:48:37 · 142 阅读 · 2 评论 -
剑指 Offer 25. 合并两个排序的链表
思路:双指针,引入哨兵节点ListNode dum = new ListNode(0), cur = dum;,最后返回dum.next注意点:如果两个链表的长度不同,跳出循环后,有了l1 == null || l2 == null,将较长的链表挂在cur后面即可,也就是cur.next = l1 != null ? l1 : l2;/** * Definition for singly-linked list. * public class ListNode { * int val;.原创 2021-01-10 14:38:12 · 92 阅读 · 0 评论