内容来源于自己的刷题笔记,对一些题目进行方法总结,用 java 语言实现。
11. 将单链表的每 K 个节点之间逆序:
-
题目描述:
给定一个单链表的头节点 head,实现一个调整单链表的函数,使得每 K 个节点之间逆序,如果不够 K 个节点一组,则不调整最后几个节点。
-
解题思路:
-
方法一:利用栈结构
- 从左到右遍历链表,如果栈的大小不等于 K,就将节点不断压入栈中
- 当栈的大小第一次达到 K 时,说明第一次凑齐了 K 个节点进行逆序,从栈中依次弹出这些节点,并根据弹出的顺序重新连接,这一组逆序后,需要记录一下新的头部,同时第一组的最后一个节点(原来是头节点)应该连接下一个节点
- 当栈的大小每次达到 K 时,说明又凑齐了一组应该逆序的节点,从栈中依次弹出这些节点,并根据弹出的顺序重新连接,直到链表都被遍历完
- 最后应该返回 newHead,作为链表新的头节点
-
方法二:在原链表上进行调整
用变量记录每一组开始的第一个节点和最后一个节点,然后直接进行调整,把这一组的节点都逆序。同样,也是要注意第一组节点的特殊处理。
-
-
代码实现:
public class ReverseKNode { private class Node{ public int value; public Node next; public Node(int value){ this.value = value; } } /** * 使用栈结构 * @param head * @param K * @return */ public Node reverseKNodes1(Node head,int K){ if (K < 2) return head; Stack<Node> stack = new Stack<>(); Node newHead = head; Node cur = head; Node pre = null; Node next = null; while (cur != null){ next = cur.next; stack.push(cur); if (stack.size() == K){ pre = resign1(stack,pre,next); newHead = newHead == head ? cur : newHead; } cur = next; } return newHead; } public Node resign1(Stack<Node> stack,Node left,Node right){ Node cur = stack.pop(); if (left != null){ left.next = cur; } Node next = null; while (!stack.isEmpty()){ next = stack.pop(); cur.next = next; cur = next; } cur.next = right; return cur; } /** * 直接在原链表上进行操作 * @param head * @param K * @return */ public Node reverseKNodes2(Node head,int K){ if (K < 2){ return head; } Node cur = head; Node start = null; Node pre = null; Node next = null; int count = 1; while (cur != null){ next = cur.next; if (count == K){ start = pre == null ? head : pre.next; head = pre == null ? cur : head; resign2(pre,start,cur,next); pre = start; count = 0; } count++; } return head; } public void resign2(Node left,Node start,Node end,Node right){ Node pre = start; Node cur = start.next; Node next = null; while (cur != right){ next = cur.next; cur.next = pre; pre = cur; cur = next; } if (left != null){ left.next = end; } start.next = right; } }
12. 删除无序链表中值重复出现的节点:
-
题目描述:
给定一个无序单链表的头节点 head,删除其中值重复出现的节点
-
解题思路:
-
方法一:利用哈希表
- 生成一个哈希表,因为头节点是不需要删除的节点,所以首先将头节点的值放入哈希表
- 从头节点的下一个节点开始往后遍历节点,假设遍历到 cur 节点,先检查 cur 的值是否在哈希表中,如果在,则说明 cur 节点的值在之前就出现过,就将 cur 节点删除,删除的方式就是将最近一个没有被删除的节点 pre 连接到 cur 的下一个节点;如果不是,就将 cur 节点放入哈希表中
-
方法二:类似选择排序的过程
定义两个循环,到第一个节点,往后循环是否有值相同的节点,有就删除,以此类推,直到全部删除完毕
-
-
代码实现:
public class RemoveRep { private class Node{ public int value; public Node next; public Node(int value){ this.value = value; } } public void removeRep1(Node head){ if (head == null){ return; } HashSet<Integer> set = new HashSet<>(); Node pre = head; Node cur = pre.next; set.add(head.value); while (cur != null){ if (set.contains(cur.value)){ pre.next = cur.next; }else{ pre = cur; } cur = cur.next; } } public void removeRep2(Node head){ Node cur = head; Node pre = null; Node next = null; while (cur != null){ pre = cur; next = cur.next; while (next != null){ if (cur.value == next.value){ pre.next = next.next; }else { pre = next; } next = next.next; } cur = cur.next; } } }
13. 在单链表中删除指定值的节点:
-
题目描述:
给定一个链表的头节点 head 和一个整数 num,请实现函数将值为 num 的节点全部删除
-
解题思路:
-
方法一:利用栈结构
将值不等于 num 的节点用栈收集起来,收集完成后重新连接,最后将栈底的节点作为新的头节点返回
-
方法二:在原链表中调整
- 从链表头进行遍历,找到第一个值不等于 num 的节点,作为新的头节点,记为 newHead
- 继续往后遍历,假设当前节点的值等于 num,就删除;不等于就更新到最近一个不等于 num 的节点
-
-
代码实现:
public class RemoveValue { private class Node{ public int value; public Node next; public Node(int value){ this.value = value; } } public Node removeValue1(Node head,int num){ Stack<Node> stack = new Stack<>(); while (head != null){ if (head.value != num){ stack.push(head); } head = head.next; } while (!stack.isEmpty()){ stack.peek().next = head; head = stack.pop(); } return head; } public Node removeValue2(Node head,int num){ while (head != null){ if (head.value != num){ break; } head = head.next; } Node pre = head; Node cur = head; while (cur != null){ if (cur.value == num){ pre.next = cur.next; }else { pre = cur; } cur = cur.next; } return head; } }
14. 将搜索二叉树转换成双向链表:
-
题目描述:
对二叉树的节点来说,有本身的值域,有指向左孩子节点和右孩子节点的两个指针;对双向链表的节点来说,有本身的值域,有指向上一个节点和下一个节点的指针。在结构上,两种结构有相似性,现在有一棵搜索二叉树,请将其转换成一个有序的双向链表
-
解题思路:
- 方法一:使用队列和中序遍历
- 生成一个队列,记为 queue,按照二叉树中序遍历的顺序,将每个节点放入 queue 中
- 从 queue 中弹出节点,并按照弹出的顺序重新连接所有节点
- 方法二:利用递归函数
- 构建一个类,属性为有序双向链表的头节点和尾节点
- 实现递归函数 process,先把 X 为头的搜索二叉树的左子树转换成有序双向链表,并且返回左子树有序双向链表的头和尾,然后把以 X 为头的搜索二叉树的右子树转换为有序双向链表,并且返回右子树有序双向链表的头和尾,接着通过 X 把两部分连接起来
- 方法一:使用队列和中序遍历
-
代码实现:
public class Convert { private class Node{ public int value; public Node left; public Node right; public Node(int value){ this.value = value; } } /** * 使用队列 * @param head * @return */ public Node convert1(Node head){ Queue<Node> queue = new LinkedList<>(); inOrderToQueue(head,queue); if (queue.isEmpty()){ return head; } Node pre = head; pre.left = null; Node cur = null; while (!queue.isEmpty()){ cur = queue.poll(); pre.right = cur; cur.left = pre; pre = cur; } pre.right = null; return head; } public void inOrderToQueue(Node head,Queue<Node> queue){ if (head == null){ return; } inOrderToQueue(head.left,queue); queue.offer(head); inOrderToQueue(head.right,queue); } private class RetrunType{ public Node start; public Node end; public RetrunType(Node start,Node end){ this.start = start; this.end = end; } } public Node convert2(Node head){ if (head == null){ return null; } return process(head).start; } /** * 递归函数 * @param head * @return */ public RetrunType process(Node head){ if (head == null){ return new RetrunType(null,null); } RetrunType leftList = process(head.left); RetrunType rightList = process(head.right); if (leftList.end != null){ leftList.end.right = head; } head.left = leftList.end; head.right = rightList.start; if (rightList.start != null){ rightList.start.left = head; } return new RetrunType(leftList.start != null ? leftList.start : head,rightList.end != null ? rightList.end : head); } }