二十一、链表[两个单链表的交点(有无环) / 回文结构]

一、单链表的相交问题

	public static class Node {
		public int value;
		public Node next;

		public Node(int data) {
			this.value = data;
		}
	}

	public static Node getIntersectNode(Node head1, Node head2) {
		if (head1 == null || head2 == null) {
			return null;
		}
		//得到入环节点
		Node loop1 = getLoopNode(head1);
		Node loop2 = getLoopNode(head2);
		if (loop1 == null && loop2 == null) {
		    //1、无环链表的相交问题
			return noLoop(head1, head2);
		}
		if (loop1 != null && loop2 != null) {
		    //2、有环链表的相交问题
			return bothLoop(head1, loop1, head2, loop2);
		}
		return null;
	}

    /**
     * 找到入环节点
     * @param head
     * @return
     */
	public static Node getLoopNode(Node head) {
		if (head == null || head.next == null || head.next.next == null) {
			return null;
		}
		Node slow = head.next; // 慢指针
		Node fast = head.next.next; // 快指针
        // 快指针==慢指针跳出循环
		while (slow != fast) {
		    // 快指针到结尾,没有环
			if (fast.next == null || fast.next.next == null) {
				return null;
			}
			fast = fast.next.next;
			slow = slow.next;
		}
		//快慢指针到相同节点的时候,快指针回到开头
		fast = head;
        //快慢指针此时每次都走一步,走到同一节点跳出循环,该节点到入环节点
		while (slow != fast) {
			slow = slow.next;
			fast = fast.next;
		}
		return slow;
	}

    /**
     * 无环链表相交问题
     * @param head1
     * @param head2
     * @return
     */
	public static Node noLoop(Node head1, Node head2) {
		if (head1 == null || head2 == null) {
			return null;
		}
		Node cur1 = head1;
		Node cur2 = head2;
		int n = 0;
		//找到链表head1的结尾
		while (cur1.next != null) {
			n++;
			cur1 = cur1.next;
		}
		// 找到链表head2的结尾
		while (cur2.next != null) {
			n--;
			cur2 = cur2.next;
		}
		// 尾节点不等,没有交点
		if (cur1 != cur2) {
			return null;
		}
		// 如果n>0 head1长 cur1指向head1,n<0 则head2长 cur1指向head2(cur1始终指向较长链表的头)
		cur1 = n > 0 ? head1 : head2;
		// 如果cur1指向head1,则cur2指向head2
		cur2 = cur1 == head1 ? head2 : head1;
		// 取绝对值
		n = Math.abs(n);
		// 较长的链表先遍历n个节点
		while (n != 0) {
			n--;
			cur1 = cur1.next;
		}
		//一起遍历,找到相交的节点
		while (cur1 != cur2) {
			cur1 = cur1.next;
			cur2 = cur2.next;
		}
		return cur1;
	}

    /**
     * 有环链表相交问题
     * @param head1
     * @param loop1
     * @param head2
     * @param loop2
     * @return
     */
	public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
		Node cur1;
		Node cur2;
		//和无环求交点类似(②)
		if (loop1 == loop2) {
			cur1 = head1;
			cur2 = head2;
			int n = 0;
			while (cur1 != loop1) {
				n++;
				cur1 = cur1.next;
			}
			while (cur2 != loop2) {
				n--;
				cur2 = cur2.next;
			}
			cur1 = n > 0 ? head1 : head2;
			cur2 = cur1 == head1 ? head2 : head1;
			n = Math.abs(n);
			while (n != 0) {
				n--;
				cur1 = cur1.next;
			}
			while (cur1 != cur2) {
				cur1 = cur1.next;
				cur2 = cur2.next;
			}
			return cur1;
		} else {
		    // 有环时的其他两种情况(① ③)
			cur1 = loop1.next;
			while (cur1 != loop1) {
				if (cur1 == loop2) {
					return loop1;
				}
				cur1 = cur1.next;
			}
			return null;
		}
	}

分析:
在这里插入图片描述

二、链表回文结构

    public static class Node {
        public int value;
        public Node next;

        public Node(int data) {
            this.value = data;
        }
    }

    // need n extra space
    public static boolean isPalindrome1(Node head) {
        Stack<Node> stack = new Stack<>();
        Node cur = head;
        // 原链表压入栈中
        while (cur != null) {
            stack.push(cur);
            cur = cur.next;
        }
        // 遍历链表,同时出栈进行比较
        while (head != null) {
            if (head.value != stack.pop().value) {
                return false;
            }
            head = head.next;
        }
        return true;
    }

    // need n/2 extra space 后半段入栈
    public static boolean isPalindrome2(Node head) {
        if (head == null || head.next == null) {
            return true;
        }
        Node right = head.next;
        Node cur = head;
        while (cur.next != null && cur.next.next != null) {
            right = right.next;
            cur = cur.next.next;
        }
        Stack<Node> stack = new Stack<>();
        while (right != null) {
            stack.push(right);
            right = right.next;
        }
        while (!stack.isEmpty()) {
            if (head.value != stack.pop().value) {
                return false;
            }
            head = head.next;
        }
        return true;
    }
    
    // need O(1) extra space 快慢指针的使用
    public static boolean isPalindrome3(Node head) {
        if (head == null || head.next == null) {
            return true;
        }
        Node slow = head;//慢指针
        Node fast = head;//快指针
        while (fast.next != null && fast.next.next != null) { // find mid node
            slow = slow.next; // slow -> mid
            fast = fast.next.next; // fast -> end
        }
        fast = slow.next; // fast -> right part first node
        slow.next = null; // mid.next -> null
        Node n3;
        while (fast != null) { // right part convert
            n3 = fast.next; // n3 -> save next node
            fast.next = slow; // next of right node convert
            slow = fast; // slow move
            fast = n3; // fast move
        }
        n3 = slow; // n3 -> save last node
        fast = head;// fast -> left first node
        boolean res = true;
        while (slow != null && fast != null) { // check palindrome
            if (slow.value != fast.value) {
                res = false;
                break;
            }
            slow = slow.next; // left to mid
            fast = fast.next; // right to mid
        }
        slow = n3.next;
        n3.next = null;
        while (slow != null) { // recover list
            fast = slow.next;
            slow.next = n3;
            n3 = slow;
            slow = fast;
        }
        return res;
    }

    public static void printLinkedList(Node node) {
        System.out.print("Linked List: ");
        while (node != null) {
            System.out.print(node.value + " ");
            node = node.next;
        }
        System.out.println();
    }

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值