《剑指offer》算法题第七天
今日题目:
- 复杂链表的复制
- 二叉搜索树与双向链表
- 序列化二叉树
- 字符串的排序
1.复杂链表的复制
题目描述:
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
思路:
这道题比较简单的做法是利用哈希表,把旧节点当成key,把新节点当成value,然后再来建立关系,时间和空间复杂度均为O(n)
另外一种做法是将新生成的节点插入旧节点之间,然后再进行提取,时间复杂度为O(n),空间复杂度为O(1)。
代码如下:
1 //利用HashMap 2 public class Solution { 3 public RandomListNode Clone(RandomListNode pHead) 4 { 5 if(pHead == null) return null; 6 Map<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>(); 7 RandomListNode p = pHead; 8 while(p != null){ 9 map.put(p,new RandomListNode(p.label)); 10 p = p.next; 11 } 12 p = pHead; 13 while(p != null){ 14 RandomListNode new_node = map.get(p); 15 if(p.next != null) 16 new_node.next = map.get(p.next); 17 if(p.random != null) 18 new_node.random = map.get(p.random); 19 p = p.next; 20 } 21 return map.get(pHead); 22 } 23 } 24 25 26 //没用到HashMap 27 public class Solution { 28 public RandomListNode Clone(RandomListNode pHead) 29 { 30 if(pHead == null) return null; 31 RandomListNode p = pHead; 32 while(p != null){ 33 RandomListNode next = p.next; 34 p.next = new RandomListNode(p.label); 35 p.next.next = next; 36 p = next; 37 } 38 39 p = pHead; 40 while(p != null){ 41 if(p.random != null) 42 p.next.random = p.random.next; 43 p = p.next.next; 44 } 45 46 RandomListNode dummy = new RandomListNode(0); 47 RandomListNode q = dummy; 48 p = pHead; 49 while(p != null){ 50 RandomListNode tmp = p.next.next; 51 q.next = p.next; 52 q = q.next; 53 54 p.next = tmp; 55 56 p = tmp; 57 } 58 59 return dummy.next; 60 } 61 }
2. 二叉搜索树与双向链表
题目描述:
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
思路:
这道题利用二叉搜索树中序遍历序列递增的特性来求解,比较直接。
代码如下:
1 public class Solution { 2 public TreeNode Convert(TreeNode root) { 3 if(root == null) return null; 4 Stack<TreeNode> stack = new Stack(); 5 boolean flag = true; 6 TreeNode p = root; 7 TreeNode pre = null; 8 while(p != null || !stack.empty()){ 9 if(p != null){ 10 stack.push(p); 11 p = p.left; 12 }else{ 13 TreeNode node = stack.pop(); 14 if(flag){ 15 root = node; 16 flag = false; 17 } 18 if(pre != null) 19 pre.right = node; 20 node.left = pre; 21 pre = node; 22 p = node.right; 23 } 24 } 25 return root; 26 27 } 28 }
3. 序列化二叉树
题目描述:
请实现两个函数,分别用来序列化和反序列化二叉树
思路:
序列化:比较直接,先序遍历二叉树来生成序列
反序列化:也是根据先序遍历的思想来做的,但是可能比起序列化来说没那么直观。
代码如下:
1 public class Solution { 2 int index = -1; 3 String Serialize(TreeNode root) { 4 StringBuffer sb = new StringBuffer(); 5 if(root == null){ 6 sb.append("#,"); 7 return sb.toString(); 8 } 9 sb.append(root.val+","); 10 sb.append(Serialize(root.left)); 11 sb.append(Serialize(root.right)); 12 return sb.toString(); 13 } 14 TreeNode Deserialize(String str) { 15 index++; 16 int len = str.length(); 17 if(index >= len){ 18 return null; 19 } 20 String[] strr = str.split(","); 21 TreeNode node = null; 22 if(!strr[index].equals("#")){ 23 node = new TreeNode(Integer.valueOf(strr[index])); 24 node.left = Deserialize(str); 25 node.right = Deserialize(str); 26 } 27 28 return node; 29 } 30 }
4. 字符串的排列
题目描述:
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
思路:
回溯法的题目做多了这道题就不是什么难事,唯一要注意的是字符串中的字符有可能是有重复的。
参考答案给了另外一种基于交换的解法,比博主自己写的回溯要好得多,下面贴出代码给大家参考。
代码如下:
1 //博主写的回溯法 2 public class Solution { 3 public ArrayList<String> Permutation(String str) { 4 ArrayList<String> res = new ArrayList(); 5 if(str.length() == 0) return res; 6 char[] arr = str.toCharArray(); 7 Arrays.sort(arr); 8 backtrack(arr,res,new StringBuffer(),new HashSet()); 9 return res; 10 } 11 12 public void backtrack(char[] arr,ArrayList<String> res,StringBuffer sb,HashSet<Integer> visited){ 13 if(sb.length() == arr.length){ 14 res.add(sb.toString()); 15 return; 16 } 17 for(int i = 0; i < arr.length; i++){ 18 if(visited.contains(i)) continue; 19 sb.append(arr[i]); 20 visited.add(i); 21 backtrack(arr,res,sb,visited); 22 visited.remove(i); 23 sb.deleteCharAt(sb.length()-1); 24 while(i < arr.length-1 && arr[i] == arr[i+1]) i++; 25 } 26 } 27 } 28 29 30 //参考答案给的方法,强烈推荐!! 31 public class Solution { 32 public ArrayList<String> Permutation(String str) { 33 ArrayList<String> res = new ArrayList(); 34 if(str.length() == 0) return res; 35 char[] arr = str.toCharArray(); 36 backtrack(arr,res,0); 37 Collections.sort(res); 38 return res; 39 } 40 41 public void backtrack(char[] arr,ArrayList<String> res,int ind){ 42 if(ind == arr.length-1){ 43 res.add(String.valueOf(arr)); 44 return; 45 } 46 for(int i = ind; i < arr.length; i++){ 47 if(i != ind && arr[i] == arr[ind]) continue; 48 char swap = arr[ind]; 49 arr[ind] = arr[i]; 50 arr[i] = swap; 51 52 backtrack(arr,res,ind+1); 53 54 swap = arr[ind]; 55 arr[ind] = arr[i]; 56 arr[i] = swap; 57 } 58 } 59 }