判断两个链表是否相交,若相交,求交点。(假设链表不带环)
step1:在不带环的情况下对链表是否相交进行判断,即遍历两个链表,
链表的最后一个节点的值相等则表明链表相交。
step2:求交点,我们可以先对两链表的长度进行比较,使得长的链表先走长度差步,
然后两个链表一起走,当两个链表遇到第一个所对应节点的值相等时,则就是交点。
/**
*@Description: 判断两个链表是否相交,若相交,求交点(假设链表不带环)
*@Author: dyy
*/
public class ListMeet {
public static void main(String[] args) {
ListNode head1 = new ListNode("lemon");
head1.nextNode = new ListNode("lll");
head1.nextNode.nextNode = new ListNode(1);
head1.nextNode.nextNode.nextNode = new ListNode('a');
head1.nextNode.nextNode.nextNode.nextNode = new ListNode(5);
ListNode head2 = new ListNode("demon");
head2.nextNode = new ListNode("gj");
head2.nextNode.nextNode = new ListNode('a');
head2.nextNode.nextNode.nextNode = new ListNode(5);
}
public ListNode twoLikeMeet(ListNode head1,ListNode head2) {
if (head1 == null || head2 == null) {
return null;
}
int length1 = getLength(head1);
int length2 = getLength(head2);
int lengthDif = 0;
ListNode longNode;
ListNode shortNode;
if (length1 > length2) {
longNode = head1;
shortNode = head2;
lengthDif = length1 - length2;
} else {
longNode = head2;
shortNode = head1;
lengthDif = length2 - length1;
}
for (int i = 0; i < lengthDif; i++) {
longNode = longNode.nextNode;
}
while (longNode != null && shortNode != null) {
if (longNode.data == shortNode.data) {
return longNode;
}
longNode = longNode.nextNode;
shortNode = shortNode.nextNode;
}
return null;
}
public static int getLength(ListNode head) {
if (head == null) {
return 0;
}
int count = 0;
ListNode cur = head;
while (cur != null) {
count++;
cur = cur.nextNode;
}
return count;
}
public boolean hasIntersection(ListNode head1, ListNode head2){
ListNode fast = head1;
ListNode slow = head2;
if(fast==null||slow==null){
return false;
}
while (fast!=null){
fast = fast.nextNode;
}
while (slow!=null){
slow = slow.nextNode;
}
if(fast==slow){
return true;
}
return false;
}
}
/**
*@Description: 判断两个链表是否相交,若相交,求交点(假设链表不带换)测试函数
*@Author: dyy
*/
@Test
public void test_ListMeet(){
ListNode head1 = new ListNode("lemon");
head1.nextNode = new ListNode("lll");
head1.nextNode.nextNode = new ListNode(1);
head1.nextNode.nextNode.nextNode = new ListNode('a');
head1.nextNode.nextNode.nextNode.nextNode = new ListNode(5);
ListNode head2 = new ListNode("demon");
head2.nextNode = new ListNode("gj");
head2.nextNode.nextNode = new ListNode('a');
head2.nextNode.nextNode.nextNode = new ListNode(5);
ListMeet listMeet = new ListMeet();
if(listMeet.hasIntersection(head1,head2)==true){
System.out.println(listMeet.twoLikeMeet(head1,head2).data);
}else{
System.out.println("两个链表不相交");
}
}
复杂链表的复制。一个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL,现在要求实现复制这个链表,返回复制后的新链表。
step1:我们对链表的各个节点进行复制,并且在每一个节点后面添加新的节点
step2: 改变新增节点的random指针的指向
step3:对链表进行拆分
public class ComplexListClone {
public static RandomListNode RandomListNodeClone(RandomListNode head) {
if (head == null) {
return null;
}
copyNodes(head);
setCloneNode(head);
return spiltNodes(head);
}
public static void copyNodes(RandomListNode head) {
RandomListNode temp = head;
while (temp != null) {
RandomListNode cloneNode = new RandomListNode(0);
cloneNode.next = temp.next;
cloneNode.label = temp.label;
cloneNode.random = null;
temp.next = cloneNode;
temp = cloneNode.next;
}
}
public static void setCloneNode(RandomListNode head) {
RandomListNode pNode = head;
while (pNode != null) {
RandomListNode pClone = pNode.next;
if (pNode.random != null) {
pClone.random = pNode.random.next;
}
pNode = pClone.next;
}
}
public static RandomListNode spiltNodes(RandomListNode head) {
RandomListNode pNode = head;
RandomListNode cloneHead = null;
RandomListNode cloneNode = null;
if (pNode != null) {
cloneHead = pNode.next;
cloneNode = pNode.next;
pNode.next = cloneNode.next;
pNode = pNode.next;
}
while (pNode != null) {
cloneNode.next = pNode.next;
cloneNode = cloneNode.next;
pNode.next = cloneNode.next;
pNode = pNode.next;
}
return cloneHead;
}
}
/**
*@Description: 复杂链表的复制测试
*@Author: dyy
*/
@Test
public void test_ComplexListClone(){
RandomListNode randomListNode = new RandomListNode(1);
randomListNode.next = new RandomListNode(3);
RandomListNode randomListNode2 = randomListNode.next;
randomListNode.next = new RandomListNode(65);
RandomListNode randomListNode3 = randomListNode2.next;
randomListNode.next = new RandomListNode(2);
randomListNode.random = randomListNode3;
randomListNode2.random = randomListNode;
System.out.println(ComplexListClone.RandomListNodeClone(randomListNode).label);
}
求两个已排序单链表中相同的数据。
求两个已经排序好单链表中相同的数据,我们可以使用用一个链表的一个值
另外一个链表的所有值进行比较,相同则输出,但是这样的复杂度就特别高;
但我们可以使用和并两个排序好的单链表具有相同的思路,设置两个节点,
当其中一个值大时,就向后移动,相等则输出任意节点,同时移动这两个节点。
/**
*@Description: 求两个已排序链表中的相同元素
*@Author: dyy
*/
public class SortListHasEqualElements{
public static void FindEqualElements(ListNode head1,ListNode head2){
ListNode cur1 = head1;
ListNode cur2 = head2;
if(head1==null||head2==null){
System.out.println("两个链表中有其一为空");
}
int flag = 1;
if(cur1.data > cur1.nextNode.data){
flag = 0;
}
while (cur1!=null&&cur2!=null){
if(cur1.data>cur2.data){
if(0 == flag){
cur1 = cur1.nextNode;
}else{
cur2 = cur2.nextNode;
}
}else if(cur1.data==cur2.data){
System.out.print(cur1.data+"->");
cur1=cur1.nextNode;
cur2=cur2.nextNode;
}else if(cur1.data<cur2.data){
if(0==flag){
cur2 = cur2.nextNode;
}else{
cur1 = cur1.nextNode;
}
}
}
}
/**
*@Description: 求两个已排序链表中的相同元素测试函数
*@Author: dyy
*/
@Test
public void test_FindEqualElements(){
ListNode head1 = new ListNode(1);
head1.nextNode = new ListNode(3);
head1.nextNode.nextNode = new ListNode(5);
head1.nextNode.nextNode.nextNode = new ListNode(7);
ListNode head2 = new ListNode(0);
head2.nextNode = new ListNode(2);
head2.nextNode.nextNode = new ListNode(3);
head2.nextNode.nextNode.nextNode = new ListNode(5);
SortListHasEqualElements.FindEqualElements(head1,head2);
}
比较顺序表和链表的优缺点,他们分别在什么场景下使用它?
- 顺序表支持随机访问,而单链表不支持随机访问.
- 顺序表插入/删除数据效率很低,时间复杂度为O(N)(除尾插尾删),单链表插入和删除效率更高,时间复杂度为O(1).
- 顺序表的CPU高速缓存效率更高,单链表CPU高速缓存效率低.