二叉搜索树与双向链表
剑指 Offer 36. 二叉搜索树与双向链表 - 力扣(Leetcode)
题目要求
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
思路分析
我们发现二叉树转换的双向链表顺序其实就是二叉树中序遍历结果的顺序;
进行中序遍历,将pre指针指向第一个节点,cur指针指向第二个节点,进入循环;
pre.right = cur;
cur.left = pre;
pre=cur;
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 class Solution { public Node treeToDoublyList (Node root) { if (root == null ){ return null ; } Queue<Node> queue = new LinkedList <>(); inOrder(root,queue); Node head = queue.poll(); Node pre = head; while (!queue.isEmpty()){ Node cur = queue.poll(); pre.right = cur; cur.left = pre; pre = cur; } pre.right = head; head.left = pre; return head; } void inOrder (Node root,Queue<Node> queue) { if (root == null ){ return ; } inOrder(root.left,queue); queue.add(root); inOrder(root.right,queue); } }
序列化二叉树
剑指 Offer 37. 序列化二叉树 - 力扣(Leetcode)
题目要求
请实现两个函数,分别用来序列化和反序列化二叉树。
你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
例子:
1 2 输入:root = [1 ,2 ,3 ,null ,null ,4 ,5 ] 输出:[1 ,2 ,3 ,null ,null ,4 ,5 ]
思路分析
序列化:保存前序遍历结果,保存到数组中,然后使用split分割为字符串;
反序列化:定义一个队列,将头节点放入,进入循环;1. 出队,2. 构建左右子节点(i++),如果左右子节点不为空则需要入队;重复1和2,直到循环结束;
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 public class Codec { public String serialize (TreeNode root) { if (root == null ){ return "" ; } StringBuilder build = new StringBuilder (); Queue<TreeNode> queue = new LinkedList <>(); queue.add(root); while (!queue.isEmpty()){ TreeNode t = queue.poll(); if (t!=null ){ queue.add(t.left); queue.add(t.right); build.append(t.val+ "," ); }else { build.append("null," ); } } return build.toString(); } public TreeNode deserialize (String data) { if (data == null || data.length()<=0 ){ return null ; } String[] str = data.split("," ); Queue<TreeNode> queue = new LinkedList <>(); TreeNode root = new TreeNode (Integer.parseInt(str[0 ])); queue.add(root); int i = 1 ; while (!queue.isEmpty()){ TreeNode t = queue.poll(); if (!str[i].equals("null" )){ TreeNode left = new TreeNode (Integer.parseInt(str[i])); t.left = left; queue.add(left); } i++; if (!str[i].equals("null" )){ TreeNode right = new TreeNode (Integer.parseInt(str[i])); t.right = right; queue.add(right); } i++; } return root; } }
字符串的排列
剑指 Offer 38. 字符串的排列 - 力扣(Leetcode)
题目要求
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
例子:
1 2 输入:s = "abc" 输出:["abc" ,"acb" ,"bac" ,"bca" ,"cab" ,"cba" ]
提示:
1 <= s 的长度 <= 8
思路分析
使用全排列解决
将字符串的所有排列放入数组;
进入dfs,进行剪枝(arr[i] = arr[i-1] && arr[i-1] = false; 满足就不递归,否则就递归);
使用visited[i] = true,表示已经被访问;然后使用for循环对未访问过的元素进行dfs;
代码实现
时间O(n*n!) 空间O(n)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 class Solution { List<Character> path; List<String> res; boolean [] visited; public String[] permutation(String s) { this .path = new ArrayList <>(); this .res = new ArrayList <>(); this .visited = new boolean [s.length()]; char [] arr = s.toCharArray(); Arrays.sort(arr); dfs(arr,0 ); String[] str = new String [res.size()]; for (int i=0 ;i<res.size();i++){ str[i] = res.get(i); } return str; } void dfs (char [] arr,int k) { if (arr.length == k){ res.add(listToString(path)); return ; } for (int i=0 ;i<arr.length;i++){ if (i>0 && arr[i] == arr[i-1 ] && visited[i-1 ] == false ){ continue ; } if (visited[i] == false ){ visited[i] = true ; path.add(arr[i]); dfs(arr,k+1 ); path.remove(path.size() - 1 ); visited[i] = false ; } } } String listToString (List<Character> list) { StringBuilder build = new StringBuilder (); for (int i=0 ;i<list.size();i++){ build.append(list.get(i)); } return build.toString(); } }
数组中出现次数超过一半的数字
剑指 Offer 39. 数组中出现次数超过一半的数字 - 力扣(Leetcode)
题目要求
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
例子:
1 2 输入: [1 , 2 , 3 , 2 , 2 , 2 , 5 , 4 , 2 ] 输出: 2
提示:
1 <= 数组长度 <= 50000
思路分析
哈希表,使用哈希表存放数值以及数值出现的次数,然后和1 2 n {1\over 2}n 2 1 n 进行比较;(O(n) O(n))
排序法,中位数一定是众数;(O(nlogn) O(1))
摩尔投票法,(O(n) O(1)):
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public int majorityElement (int [] nums) { if (nums.length <= 2 ){ return nums[0 ]; } int x = nums[0 ]; int sum = 1 ; for (int i=1 ;i<nums.length;i++){ if (sum == 0 ){ x = nums[i]; sum = 1 ; }else { if (x == nums[i]){ sum++; }else { sum--; } } } return x; } }
最小的k个数
剑指 Offer 40. 最小的k个数 - 力扣(Leetcode)
题目要求
输入整数数组 arr
,找出其中最小的 k
个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
例子:
1 2 3 4 5 输入:arr = [3 ,2 ,1 ], k = 2 输出:[1 ,2 ] 或者 [2 ,1 ] 输入:arr = [0 ,1 ,2 ,1 ], k = 1 输出:[0 ]
提示:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
思路分析
快速排序思想:选定一个点,把小于等于这个点的放到它的左边,大于这个点的放到它的右边;
堆排序:
定义一个大顶堆:Queue<Integer> heap = new PriorityQueue<>(k, (i1, i2) -> Integer.compare(i2, i1));
通过k控制堆的大小,遍历数组,并将小于堆顶的元素放入;
当堆中元素数量超过k,就将堆中最大的一个元素弹出;
直到遍历完毕,将堆中剩余的元素重新放入一个数组,返回即可;
代码实现
快排思想
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class Solution { public int [] getLeastNumbers(int [] arr, int k) { if (arr == null || arr.length == 0 || k == 0 ){ return new int [0 ]; } return quickFind(arr,0 ,arr.length-1 ,k); } int [] quickFind(int [] arr,int left,int right,int k){ int i = partition(arr,left,right); if (i+1 == k){ return Arrays.copyOf(arr,k); } if (i+1 > k){ return quickFind(arr,0 ,i-1 ,k); }else { return quickFind(arr,i+1 ,right,k); } } int partition (int [] arr,int left,int right) { int pivot = arr[left]; int i = left+1 ; int j = right; while (i<j){ while (i<=j && arr[i]<=pivot) i++; while (i<=j && arr[j]>=pivot) j--; if (i>=j){ break ; } int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } arr[left] = arr[j]; arr[j] = pivot; return j; } }
堆排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution { public int [] getLeastNumbers(int [] arr, int k) { if (k == 0 ) { return new int [0 ]; } Queue<Integer> heap = new PriorityQueue <>(k, (i1, i2) -> Integer.compare(i2, i1)); for (int e : arr) { if (heap.isEmpty() || heap.size() < k || e < heap.peek()) { heap.offer(e); } if (heap.size() > k) { heap.poll(); } } int [] res = new int [heap.size()]; int j = 0 ; for (int e : heap) { res[j++] = e; } return res; } }