鏈表的常見面試題

先說下一個節點的結構:一個val域和一個next域

public class ListNode {
	int val;
	ListNode next = null;
	public ListNode(int val) {
		this.val = val;
	}
}

一、已知鏈表的頭節點,將鏈表進行逆序。(不可以申請額外的空間)

public static ListNode reverseList(ListNode node) {
	ListNode pre = null;
	ListNode pNext = null;
	while(node != null) {
		pNext = node.next;
		node.next = pre;
		pre = node;
		node = pNext;
	}
	return pre;
}

二、已知鏈表的頭節點,將鏈表從位置m到n逆序。注意:1<=m<=n<=鏈表長度(不允許申請額外空間)

思路:主要是要找到逆序的頭節點和尾巴,以及頭節點的前驅節點,和尾節點的後置節點

注意:如果m=1,說明是從第一個節點開始,那麼就需要修改頭節點

public static ListNode reverseListBetween(ListNode node,int m,int n) {
	int index = 1;
	ListNode p = node;
	ListNode pre = null;
	while(index <= n) {
		if(index == m) {
			ListNode temp = p;
			ListNode tempPre = null;
			ListNode tempNext = null;
			for(int i = m;i <= n;i++) {//開始進行節點的逆序
				tempNext = temp.next;
				temp.next = tempPre;
				tempPre = temp;
				temp = tempNext;
			}
			if(pre == null) {//說明是從頭節點就開始翻轉
				p.next = temp;
				node = tempPre;//修改下頭節點
			}else {
				pre.next = tempPre;
				p.next = temp;
			}
			index = n;
		}
		pre = p;
		p = p.next;
		index++;
	}
	return node;
}

三、求兩個鏈表公共的節點,若沒有則返回null

解題思路:給個圖就能知道!!!!從相同的位置開始判斷。交點之後都是相同的。

public static ListNode getIntersectionNode(ListNode node1,ListNode node2) {
	//先求兩個鏈表的長度
	int len1 = getLengthOfList(node1);
	int len2 = getLengthOfList(node2);
	//將指針移動到相同的位置
	if(len1 > len2) {
		for(int i = 0; i < len1 - len2;i++) 
			node1 = node1.next;
	}else {
		for(int i = 0; i < len2 - len1;i++) 
			node2 = node2.next;
	}
	//找相同的節點
	while(node1 != null && node2 != null) {
		if(node1 == node2)
			return node1;
		node1 = node1.next;
		node2 = node2.next;
	}
	return null;
}
public static int getLengthOfList(ListNode node) {
	int len = 0;
	ListNode p = node;
	while(p != null) {
		len++;
		p = p.next;
	}
	return len;
}

四、判斷一個鏈表中是否有環,若有則返回環的入口,若沒有則返回null

思路:設置快慢指針。

public static ListNode detectCycle(ListNode node) {
	ListNode fast = node;
	ListNode low = node;
	while(low!=null && fast!=null && low.next != null && fast.next !=null) {
        low = low.next;
		fast = fast.next.next;
		if(low == fast) {
			//設置一個指針從頭節點開始
			ListNode temp = node;
			while(temp != low) {
				temp = temp.next;
				low = low.next;
			}
			return temp;
		}
	}
	return null;
}

五、鏈表劃分:給定一個值x,將所有小於x的節點放在大於或等於x的節點前,且要保持這些節點原來的相對位置

解題思路:若是數組的話,實際上修改下排序的規則,並選擇一種穩定的排序即可,但是鏈表採用排序的方式就會稍微複雜。實際上可以設置兩個節點,遍歷鏈表,將小於x的節點連接到一個節點,將大於或等於x的節點連接到另外一個節點,最後再將兩個鏈表合併。

public static ListNode partition(ListNode node,int val) {
	ListNode A = new ListNode(val);
	ListNode B = new ListNode(val);
	ListNode p1 = A;
	ListNode p2 = B;
	while(node != null) {
		if(node.val < val) {
			p1.next = node;
			p1 = p1.next;
		}else {
			p2.next = node;
			p2 = p2.next;
		}
		node = node.next;
	}
	p1.next = B.next;
	p2.next = null;
	return A.next;
}

六、複雜鏈表的複製。

結點結構有三部分:一個值域 一個next域,一個隨即域 ,指向任意節點。

public class RandomListNode {
	int val;
	RandomListNode next = null;
	RandomListNode random = null;
	public RandomListNode(int val) {
		this.val = val;
	}
}

 

public static RandomListNode copyRandomListNode(RandomListNode node) {
	if(node == null)
		return null;
	//先複製節點
	RandomListNode p = node;
	while(p != null) {
		RandomListNode temp = new RandomListNode(p.val);
		temp.next = p.next;
		p.next = temp;
		p = p.next.next;
	}
	//複製節點的指向
	p = node;
	while(p != null) {
		if(p.random != null) {
			p.next.random = p.random.next;
		}
		p = p.next.next;
	}
	//拆分
	p = node;
	RandomListNode head = p.next;
	RandomListNode t = head;
	while(t.next != null) {
		p.next = t.next;
		t.next = t.next.next;
		p = p.next;
		t = t.next;
	}
	p.next = null;
	return head;
}

未完待續。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章