public Node reverseList(Node p){
//头节点的上一个节点为 null
Node pre = null;
Node next = null;
while(p!= null){
next = p.next;
p.next = pre;
pre = p;
p= next;
}
}
//倒数第k个结点
ListNode findKth(ListNode head,int k){
ListNode cur=head;
ListNode now=head;
int i=0;
while(cur!=null&i++next;
}
while(cur!=null){
now=now->next;
cur=cur->next;
}
}
在循环的环里面,跑的快的指针一定会反复遇到跑的慢的指针 ,比如:在一个环形跑道上,两个运动员在同一地点起跑,一个运动员速度快,一个运动员速度慢。当两人跑了一段时间,速度快的运动员必然会从速度慢的运动员身后再次追上并超过,原因很简单,因为跑道是环形的。
/**
* 判断单链表是否存在环
* @param head
* @return
*/
public static boolean isLoopList(ListNode head){
ListNode slowPointer, fastPointer;
//使用快慢指针,慢指针每次向前一步,快指针每次两步
slowPointer = fastPointer = head;
while(fastPointer != null && fastPointer.next != null){
slowPointer = slowPointer.next;
fastPointer = fastPointer.next.next;
//两指针相遇则有环
if(slowPointer == fastPointer){
return true;
}
}
return false;
}
一种方式可以借助两个栈,比较出最后一个相同的结点,即第一个公共节点,空间复杂度是O(m+n),有没有更好的实现方式?
其实解决这个问题还有一个更简单的办法:首先遍历两个链表得到他们的长度,就能知道哪个链表比较长,以及长的链表比短的链表多几个结点。在第二次遍历的时候,在较长的链表上先走若干步,接着同时在两个链表上遍历,找到的第一个相同的结点就是他们的第一个公共结点
public class Solution {
public static void main(String[] args) {
//构造链表结构测试用
ListNode a = new ListNode(1);
ListNode b = new ListNode(2);
ListNode c = new ListNode(3);
ListNode d = new ListNode(4);
ListNode e = new ListNode(5);
ListNode f = new ListNode(6);
ListNode g = new ListNode(7);
//第一个List
a.next = b;
b.next = c;
c.next = f;
f.next = g;
//第二个List
d.next = e;
e.next = f;
f.next = g;
Long begintime = System.nanoTime();
ListNode result = FindFirstCommonNode(a,d);
Long endtime = System.nanoTime();
if(result!=null){
System.out.println("两个链表的第一个公共节点为:"+result.val+",运行时间:"+(endtime - begintime) + "ns");
}else{
System.out.println("两个链表不相交");
}
}
public static ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
int count1 = 0;
int count2 = 0;
ListNode commonNode = null;
ListNode pNode1 = pHead1;
ListNode pNode2 = pHead2;
//得到链表1的长度
while(pNode1!=null){
count1++;
pNode1 = pNode1.next;
}
//得到链表2的长度
System.out.println("List1的长度为:"+count1);
while(pNode2!=null){
count2++;
pNode2 = pNode2.next;
}
System.out.println("List1的长度为:"+count2);
//令pNode1和pNode2重新指向头结点
pNode1 = pHead1;
pNode2 = pHead2;
int sub = count1 - count2;
System.out.println("两个List相差"+sub+"个节点");
//先在长链表上走几步,再同时在两个链表上遍历
if(sub>0){
for(int i = 0;i < sub;i++){
pNode1 = pNode1.next;
}
}else{
for(int i = 0;i < Math.abs(sub);i++){
pNode2 = pNode2.next;
}
}
System.out.println("List1从"+pNode1.val+"开始比较,List2从"+pNode2.val+"开始比较");
//得到第一个公共节点
while(pNode1!=null && pNode2!=null){
if(pNode1!=pNode2){
pNode1 = pNode1.next;
pNode2 = pNode2.next;
}else{
commonNode = pNode1;
return commonNode;
}
}
return commonNode;
}
}
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
ListNode head = new ListNode(-1);
ListNode cur = head;
while (list1 != null && list2 != null) {
if (list1.val <= list2.val) {
cur.next = list1;
list1 = list1.next;
} else {
cur.next = list2;
list2 = list2.next;
}
cur = cur.next;
}
if (list1 != null)
cur.next = list1;
if (list2 != null)
cur.next = list2;
return head.next;
}
}
在一般实现的快速排序中,我们通过首尾指针来对元素进行切分,下面采用快排的另一种方法来对元素进行切分。
我们只需要两个指针p1和p2,这两个指针均往next方向移动,移动的过程中保持p1之前的key都小于选定的key,p1和p2之间的key都大于选定的key,那么当p2走到末尾时交换p1与key值便完成了一次切分
public ListNode sortList(ListNode head) {
//采用快速排序
quickSort(head, null);
return head;
}
public static void quickSort(ListNode head, ListNode end) {
if (head != end) {
ListNode node = partion(head, end);
quickSort(head, node);
quickSort(node.next, end);
}
}
public static ListNode partion(ListNode head, ListNode end) {
ListNode p1 = head, p2 = head.next;
//走到末尾才停
while (p2 != end) {
//大于key值时,p1向前走一步,交换p1与p2的值
if (p2.val < head.val) {
p1 = p1.next;
int temp = p1.val;
p1.val = p2.val;
p2.val = temp;
}
p2 = p2.next;
}
//当有序时,不交换p1和key值
if (p1 != head) {
int temp = p1.val;
p1.val = head.val;
head.val = temp;
}
return p1;
}
归并排序应该算是链表排序最佳的选择了,保证了最好和最坏时间复杂度都是nlogn,而且它在数组排序中广受诟病的空间复杂度在链表排序中也从O(n)降到了O(1)。
归并排序的一般步骤为:
首先用快慢指针(快慢指针思路,快指针一次走两步,慢指针一次走一步,快指针在链表末尾时,慢指针恰好在链表中点)的方法找到链表中间节点,然后递归的对两个子链表排序,把两个排好序的子链表合并成一条有序的链表。
public ListNode sortList(ListNode head) {
//采用归并排序
if (head == null || head.next == null) {
return head;
}
//获取中间结点
ListNode mid = getMid(head);
ListNode right = mid.next;
mid.next = null;
//合并
return mergeSort(sortList(head), sortList(right));
}
/**
* 获取链表的中间结点,偶数时取中间第一个
*
* @param head
* @return
*/
private ListNode getMid(ListNode head) {
if (head == null || head.next == null) {
return head;
}
//快慢指针
ListNode slow = head, quick = head;
//快2步,慢一步
while (quick.next != null && quick.next.next != null) {
slow = slow.next;
quick = quick.next.next;
}
return slow;
}
/**
*
* 归并两个有序的链表
*
* @param head1
* @param head2
* @return
*/
private ListNode mergeSort(ListNode head1, ListNode head2) {
ListNode p1 = head1, p2 = head2, head;
//得到头节点的指向
if (head1.val < head2.val) {
head = head1;
p1 = p1.next;
} else {
head = head2;
p2 = p2.next;
}
ListNode p = head;
//比较链表中的值
while (p1 != null && p2 != null) {
if (p1.val <= p2.val) {
p.next = p1;
p1 = p1.next;
p = p.next;
} else {
p.next = p2;
p2 = p2.next;
p = p.next;
}
}
//第二条链表空了
if (p1 != null) {
p.next = p1;
}
//第一条链表空了
if (p2 != null) {
p.next = p2;
}
return head;
}
https://www.cnblogs.com/morethink/p/8452914.html
https://blog.csdn.net/kongmin_123/article/details/82315013