更多见手撕代码全集
public class LinkNode{
int value; //数据域
LinkNode next; //下一节点
}
从尾到头打印链表
//利用栈的先进后出的特性
public static void reversePrint(LinkNode head){
if (head== null)
return;
Stack<LinkNode> stack = new Stack<>();
while (head != null){
stack.push(head);
head= head.next;
}
while (!stack.isEmpty()){
System.out.println(stack.pop().value);
}
}
//递归的形式
public static void rePrint(LinkNode head){
if (head!= null){
rePrint(head.next);
System.out.println(head.value);
}
}
在O(1)时间删除链表结点
public static ListNode deleteNode(ListNode head, ListNode node){
if (head == null || node == null) //有一个节点为null,直接返回head;
return head;
if (head == node){ //删除头节点
return head.next;
}else if (node.next == null){ //node为尾节点,或node不在链表上的单节点
ListNode p = head;
while (p.next != node && p.next != null){//p.next != null =>找不到node,直接退出
p = p.next;
}
p.next = null;//找不到node,链表不做改变,否则去掉node
}else{//node必须在链表上,否则时间复杂度不符合条件
node.value = node.next.value; //下一节点value,给node,
node.next = node.next.next; //删除node的下一节点
}
return head;
}
链表中倒数第k个结点
用双指针 或者 栈特性
//双指针,p1、p2
public static LinkNode kNode(LinkNode head, int k){
LinkNode p1 = head;
LinkNode p2 = head;
for (int i = 0; i < k; i++) {//p1先走K步
p1 = p1.next;
}
while (p1 != null){ //当p1为null时,p2为倒数第k个节点
p1 = p1.next;
p2 = p2.next;
}
return p2;
}
反转链表
//头部插入法 迭代方式
public static LinkNode reverse(LinkNode head){
LinkNode p1 = head;
LinkNode p2 = null;
while (head != null){
head = head.next; //头节点head后移
p1.next = p2; //将p1的节点加到新链表头部
p2 = p1; //p2指到新链表头部
p1 = head; //p1继续指向原链表的目前的第一个节点
}
return p2; //返回新链表第一个节点
}
/**
* @param head 原始链表的头节点
* @return 递归方式,返回:翻转后链表的 头节点
*/
public Node reverse(Node head){
if(head == null || head.next == null) return head;
// 找到最后一个节点,作为反转链表的头节点
Node node = reverse(head.next);
// 倒数第二个节点的next,即为最后一个节点,next -》指向 倒数第二个节点
head.next.next = head;
// 倒数第二个节点 next 指向 null
head.next = null;
return node;
}
合并两个排序的链表
//类似于 归并排序的合并部分
public static LinkNode all(LinkNode head1, LinkNode head2){
if (head1 == null)
return head2;
if (head2 == null)
return head1;
LinkNode head = new LinkNode();
LinkNode p = head;
while (head1 != null && head2 != null){
if (head1.value < head2.value){
p.next = head1;
head1 = head1.next;
}else {
p.next = head2;
head2 = head2.next;
}
p = p.next;
}
if (head1 != null)
p.next = head1;
if (head2 != null)
p.next = head2;
return head.next;
}
//递归
public static LinkNode all(LinkNode head1, LinkNode head2){
if (head1 == null)
return head2;
if (head2 == null)
return head1;
LinkNode head = null;
if (head1.value < head2.value){
head = head1;
head.next = all3(head1.next, head2);
}else {
head = head2;
head.next = all3(head1, head2.next);
}
return head;
}
复杂链表的复制(重要、难)
public static LinkNode copyLink(LinkNode head){
if (head == null)
return head;
copy(head); //next节点的复制
addRandom(head); //random节点的指向复制
return splitLink(head); //节点拆分
}
public static void copy(LinkNode head){
while (head != null){
LinkNode node = new LinkNode(head.value); //new节点
node.next = head.next;
head.next = node;
head = node.next;
}
}
public static void addRandom(LinkNode head){
if (head == null)
return;
while (head != null){
if (head.random != null){
head.next.random = head.random.next;
}
head = head.next.next;
}
}
public static LinkNode splitLink(LinkNode head){
if (head == null)
return null;
LinkNode newHead = head.next;
LinkNode node = newHead;
while (node.next != null){
head.next = node.next;
head = head.next;
node.next = head.next;
node = node.next;
}
head.next = node.next;
return newHead;
}
两链表的第一个公共祖先
public static LinkNode findFirstCommonNode(LinkNode head1, LinkNode head2) {
int length1 = getListLength(head1);
int length2 = getListLength(head2);
int diff = length1 - length2;
LinkNode longListHead = head1;
LinkNode shortListHead = head2;
if (diff < 0) {
longListHead = head2;
shortListHead = head1;
diff = length2 - length1;
}
for (int i = 0; i < diff; i++) {
longListHead = longListHead.next;
}
while (longListHead != null && shortListHead != null && longListHead != shortListHead) {
longListHead = longListHead.next;
shortListHead = shortListHead.next;
}
return longListHead;// 返回第一个相同的公共结点,如果没有返回null
}
private static int getListLength(LinkNode head) {
int result = 0;
while (head != null) {
result++;
head = head.next;
}
return result;
}
找出链表中 环的入口结点
1.计算环中的节点数n;
2.p1、p2指针,p1先走n步,然后p1、p2一起走,直到p1、p2重合,说明p1在后面赶上p2,可知当前节点即是入口节点;
public static LinkNode getNode(LinkNode head){
LinkNode p1 = head;
LinkNode p2 = head;
while (p1 != null && p1.next != null){
p1 = p1.next.next;
p2 = p2.next;
if (p1 == p2){
break;
}
}
if (p1 == null || p1.next == null)//p1遍历到null,则没有环
return null;
p1 = head;
while (p1 != p2){
p1 = p1.next;
p2 = p2.next;
}
return p1;
}
删除排序链表中重复的结点
//去掉排序链表重复节点
public static LinkNode get(LinkNode head){
if (head == null)
return head;
LinkNode root = new LinkNode();
root.next = head;
LinkNode p1 = head;
LinkNode p2 = head.next;
while (p2 != null){
while (p2 != null && p1.value == p2.value){//找到第一个和p1不同节点
p2 = p2.next;
}
p1.next = p2;//p1连接第一个不同节点
p1 = p2; //等价于p1 = p1.next; -> p1向后移动
}
return root.next;
}