链表问题(Java)

提示:面试时链表解题方法论
1.对于笔试,不用太在乎空间复杂度,一切为了时间复杂度
2.对于面试,时间复杂度依然放在第一位,但是一定要找到空间最省的方法


前言

本文主要讲解了几道与链表有关的基础提醒,帮助读者更好的运用链表,对这种数据结构有更好的掌握。


一、快慢指针

  1. 输入链表头结点,奇数长度返回中点,偶数长度返回上中点。
  2. 输入链表头结点,奇数长度返回中点,偶数长度返回下中点。
  3. 输入链表头结点,奇数长度返回中点前一个,偶数长度返回上中点前一个。
  4. 输入链表头结点,奇数长度返回中点前一个,偶数长度返回下中点前一个。
package LinkedList;

import LinkedList.PatitionList.node;

public class FastAndSlowPointer {
	
	public class node{
		node next;
		int val;
		
		public node(int val) {
			this.val = val;
			this.next = null;
		}
		
		public node(int val, node next) {
			this.val = val;
			this.next = next;
		}
		
		public String toString() {
			String ans = "";
			node cur = this;
			while(cur != null) {
				ans += Integer.toString(cur.val);
				cur = cur.next;
			}
			return ans;
		}
	}
	
	public int ReturnUpMid(node head) {
		if(head == null) return -1;
		int ans;
		node fast = head;
		node slow = head;
		while(fast.next != null && fast.next.next != null) {
			fast = fast.next.next;
			slow = slow.next;
		}
		ans = slow.val;
		return ans;
	}
	
	public int ReturnLowMid(node head) {
		if(head == null) return -1;
		int ans;
		node fast = head;
		node slow = head;
		while(fast.next != null && fast.next.next != null) {
			fast = fast.next.next;
			slow = slow.next;
		}
		if(fast.next != null) slow = slow.next;				//如果是偶数,慢指针再走一次
		ans = slow.val;
		return ans;
	}

	public int ReturnFrontUpMid(node head) {
		if(head == null) return -1;
		if(head.next == null) return -1;
		int ans;
		node fast = head;
		node slow = head;
		if(fast.next != null && fast.next.next != null) {	//快指针多走一步(慢指针少走一步)
			fast = fast.next.next;
		}
		while(fast.next != null && fast.next.next != null) {
			fast = fast.next.next;
			slow = slow.next;
		}
		ans = slow.val;
		return ans;
	}
	
	public int ReturnFrontLowMid(node head) {
		if(head == null) return -1;
		if(head.next == null) return -1;
		int ans;
		node fast = head;
		node slow = head;
		if(fast.next != null && fast.next.next != null) {	//快指针多走一步(慢指针少走一步)
			fast = fast.next.next;
		}
		while(fast.next != null && fast.next.next != null) {
			fast = fast.next.next;
			slow = slow.next;
		}
		if(fast.next != null) slow = slow.next;
		ans = slow.val;
		return ans;
	}
	
	public static void main(String[] args) {
		FastAndSlowPointer f = new FastAndSlowPointer();
		node head = new FastAndSlowPointer().new node(0);
		node one = new FastAndSlowPointer().new node(1);
		node two = new FastAndSlowPointer().new node(2);
		node three = new FastAndSlowPointer().new node(3);
		node four = new FastAndSlowPointer().new node(4);
		node five = new FastAndSlowPointer().new node(5);
		node six = new FastAndSlowPointer().new node(6);
		
		head.next = one;
		one.next = two;
		two.next = null;
		
		three.next = four;
		four.next = five;
		five.next = six;
		six.next = null;
		
		System.out.println("奇数原串:" + head);
		System.out.println("偶数原串:" + three);
		
		// 0, 1, 2
		//3, 4, 5, 6
		//返回上中点
		System.out.println("返回上中点");
		System.out.println("奇数" + f.ReturnUpMid(head));
		System.out.println("偶数" + f.ReturnUpMid(three));
		
		//返回下中点
		System.out.println("返回下中点");
		System.out.println("奇数" + f.ReturnLowMid(head));
		System.out.println("偶数" + f.ReturnLowMid(three));
		
		//返回上中点前一个
		System.out.println("返回上中点前一个");
		System.out.println("奇数" + f.ReturnFrontUpMid(head));
		System.out.println("偶数" + f.ReturnFrontUpMid(three));
		
		//返回下中点前一个
		System.out.println("返回下中点前一个");
		System.out.println("奇数" + f.ReturnFrontLowMid(head));
		System.out.println("偶数" + f.ReturnFrontLowMid(three));
	}
}

运行结果
在这里插入图片描述

二、判断链表回文

共有两种方法,

  1. 找到中点,之后将前一部分的值存储起来。再倒序与后半部分做对比。时间复杂度O(n) 空间复杂度O(n)
    2.找到中点,之后将后一部分链表反转,中点指空,得到两个链表,则两个链表按序对比。对比完成后将链表还原。时间复杂度O(n) 空间复杂度O(1)
package LinkedList;

import java.util.LinkedList;
import java.util.List;

public class JudgementPalindrome {
	public class node{
		int val;
		node next;
		
		public node(int val) {
			this.val = val;
			this.next = null;
		}
		
		public node(int val, node next) {
			this.val = this.val;
			this.next = next;
		}
		
		public node insert(int val) {
			node next = new node(val);
			node cur = this;
			while(cur.next != null) {
				cur = cur.next;
			}
			cur.next = next;
			return this;
		}
		
		public String toString() {
			String ans = "";
			node cur = this;
			while(cur != null) {
				ans += Integer.toString(cur.val);
				cur = cur.next;
			}
			return ans;
		}
	}
	
	public node[] findUpMid(node head) {
		if(head == null) return null;
		node slow = head;
		node fast = head;
		while(fast.next != null && fast.next.next != null) {
			slow = slow.next;
			fast = fast.next.next;
		}
		if(fast.next != null) {
			return new node[] {slow, slow.next};
		}
		return new node[] {slow, slow};
	}
	
	public boolean method1(node head) {			//找到中点位置,之后比较相当于将链表对着 时间复杂度O(n) 空间复杂度O(n)
		boolean ans = true;
		node[] mid = this.findUpMid(head);
		if(mid == null) return ans;
//		System.out.println("中点:" + mid[0].val + " " + mid[1].val);
		node cur = head;
		List<Integer> list = new LinkedList<>();
		while(cur != mid[0].next) {
			list.add(cur.val);
			cur = cur.next;
		}
		cur = mid[1];
		int size = list.size();
		for(int i = size - 1; i >= 0; --i) {
			if(cur == null || cur.val != list.get(i)) {
				ans = false;
				break;
			}
			cur = cur.next;
		}
		return ans;
	}
	
	//链表反转
	public node reverse(node head) {
		if(head == null || head.next == null) return head;
		node p1 = head;
		node p2 = head.next;
		head.next = null;		//头变尾
		while(p2 != null) {
			node next = p2.next;
			p2.next = p1;
			p1 = p2;
			p2 = next;
		}
		return p1;
	}
	
	public boolean method2(node head) {		//找到中点位置,然后将后半部分反转,之后遍历两个链表同时进行比较,比较完成后将链表复原 时间复杂度O(n) 空间复杂度O(1)
		boolean ans = true;
		node[] mid = this.findUpMid(head);
		if(mid == null) return ans;
		node head2 = reverse(mid[1]);
		mid[0].next = null;		//拆分
		node cur1 = head;
		node cur2 = head2;
		while(cur1 != null && cur2 != null) {
			if(cur1.val != cur2.val) {
				ans = false;
				break;
			}
			cur1 = cur1.next;
			cur2 = cur2.next;
		}
		if(cur1 != null || cur2 != null) {
			ans = false;
		}
		
		//复原链表
		head2 = reverse(head2);
		if(mid[0] != mid[1]) {		//如果两个中点不是同一个需要链接一下
			mid[0].next = mid[1];
		}
		return ans;
	}
	
	public static void main(String[] args) {
		System.out.println("—————————————————————原串———————————————————————————");
		node head1 = new JudgementPalindrome().new node(0);
		head1.insert(1).insert(2).insert(3).insert(4).insert(4).insert(3).insert(2).insert(1).insert(0);
		System.out.println("head1:" + head1);
		node head2 = new JudgementPalindrome().new node(0);
		head2.insert(1).insert(2).insert(3).insert(4).insert(3).insert(2).insert(1).insert(0);
		System.out.println("head2:" + head2);
		node head3 = new JudgementPalindrome().new node(0);
		head3.insert(1).insert(2).insert(3).insert(4).insert(3).insert(2).insert(1);
		System.out.println("head3:" + head3);
		
		System.out.println("————————————————————————————————————————————————————");
		
		JudgementPalindrome f = new JudgementPalindrome();
		
		System.out.println("方法一");
		System.out.println("偶回文串" + f.method1(head1));
		System.out.println("奇回文串" + f.method1(head2));
		System.out.println("非回文串" + f.method1(head3));
		
		System.out.println("————————————————————————————————————————————————————");
		
		System.out.println("方法二");
		System.out.println("偶回文串" + f.method2(head1));
		System.out.println("奇回文串" + f.method2(head2));
		System.out.println("非回文串" + f.method2(head3));
		
		System.out.println("————————————————————查看链表是否发生改变—————————————————————");
		System.out.println("head1:" + head1);
		System.out.println("head2:" + head2);
		System.out.println("head3:" + head3);
	}
}


运行结果
在这里插入图片描述

三、将单链表按照某值划分成左边小中间相等右边大的形式

  1. 放入数组进行partition,之后重新串联
  2. 六个指针,但要考虑某个区域可能没有值
package LinkedList;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class PatitionList {
	
	public class node{
		int val;
		node next;
		
		public node(int val) {
			this.val = val;
			this.next = null;
		}
		
		public node(int val, node next) {
			this.val = this.val;
			this.next = next;
		}
		
		public node insert(int val) {
			node next = new node(val);
			node cur = this;
			while(cur.next != null) {
				cur = cur.next;
			}
			cur.next = next;
			return this;
		}
		
		public String toString() {
			String ans = "";
			node cur = this;
			while(cur != null) {
				ans += Integer.toString(cur.val);
				cur = cur.next;
			}
			return ans;
		}
	}
	
	public node method2(node head, int key) {	//用六个指针3个链表分别进行计数	时间复杂度O(n) 空间复杂度O(1)
		node ans = null;
		//小于k的链表
		node lh = null;
		node le = null;
		//等于k的链表
		node eh = null;
		node ee = null;
		//大于k的链表
		node mh = null;
		node me = null;
		
		node cur = head;
		while(cur != null) {
			if(cur.val == key) {
				if(eh == null) {
					eh = cur;
					ee = eh;
				}else {
					ee.next = cur;
					ee = ee.next;
				}
			}else if(cur.val > key) {
				if(mh == null) {
					mh = cur;
					me = mh;
				}else {
					me.next = cur;
					me = me.next;
				}
			}else {
				if(lh == null) {
					lh = cur;
					le = mh;
				}else {
					le.next = cur;
					le = me.next;
				}
			}
			cur = cur.next;
		}
		
		if(le != null) le.next = null;
		if(me != null) me.next = null;
		if(ee != null) ee.next = null;
		
		if(le != null) {
			le.next = eh;
			ee = ee != null? ee: le;
		}
		if(ee != null) {
			ee.next = mh;
		}
		return lh != null? lh: eh != null? eh: mh;
	}
	
	
	public node partition(node head, int key) {		//将值存储在数组中,对数组进行partition再重新建立链表  时间复杂度O(n) 空间复杂度O(n)
		node ans = null;
		List<Integer> list = new LinkedList<>();
		node cur = head;
		while(cur != null) {
			list.add(cur.val);
			cur = cur.next;
		}
		
		int[] nums = new int[list.size()];
		for(int i=0; i<list.size(); ++i) {
			nums[i] = list.get(i);
		}
		partition_help(nums, key);
		ans = new node(nums[0]); 
		cur = ans;
		for(int i=1; i<nums.length; ++i) {
			cur.next = new node(nums[i]);
			cur = cur.next;
		}
		
		return ans;
	}
	
	public void partition_help(int[] nums, int key) {
		if(nums.length <= 1) return ;
		int less = 0;
		int cur = 0;
		int more = nums.length - 1;
		while(cur <= more) {
			while(nums[cur] > key && cur <= more) {
				int temp = nums[more];
				nums[more] = nums[cur];
				nums[cur] = temp;
				--more;
			}
			if(nums[cur] < key) {
				int temp = nums[less];
				nums[less] = nums[cur];
				nums[cur] = temp;
				++less;
			}
			++cur;
		}
	}
	
	public static void main(String[] argv) {
		PatitionList f = new PatitionList();
		node head = new PatitionList().new node(5);
		head.insert(5).insert(5);
		for(int i=0; i<20; ++i) {
			head.insert((int)(Math.random() * 10));
		}
		System.out.println("原              串:" + head);
		
		System.out.println("方法一排序后:" + f.partition(head, 5));
		
		System.out.println("方法二排序后:" + f.partition(head, 5));
		
	}
	
}

运行结果:
在这里插入图片描述

四、复制random单链表

链表结构比之前多一个random指针,随机指向一个节点,也可能指向空,如何对该链表进行克隆

  1. 利用HashMap对节点进行存储,key为老节点,value为克隆的新节点。分为两遍遍历,第一遍进行节点的复制,第二遍进行next与random节点的连接。时间复杂度 O(n) 空间复杂度(n)
  2. 在原节点后面加上克隆的节点,三遍遍历,第一遍进行节点的复制,并且将复制出来的节点连接到该节点的后面,克隆节点指向下一个旧节点。第二遍设置克隆节点的random节点。最后一遍将两个链表进行拆分。时间复杂度 O(n) 空间复杂度(1)
package LinkedList;

import java.util.HashMap;

import LinkedList.JudgementPalindrome.node;

public class RandomLinkClone {
	
	public class node{
		int val;
		node next;
		node random;
		
		public node(int val) {
			this.val = val;
			this.next = null;
			this.random = null;
		}
		
		public node(int val, node next) {
			this.val = val;
			this.next = next;
			this.random = null;
		}
		
		public node(int val, node next, node random) {
			this.val = val;
			this.next = next;
			this.random = random;
		}
		
		public node insert(int val) {
			node next = new node(val);
			node cur = this;
			while(cur.next != null) {
				cur = cur.next;
			}
			cur.next = next;
			return this;
		}
		
		public String toString() {
			String ans = "";
			node cur = this;
			while(cur != null) {
				ans += Integer.toString(cur.val) + " ";
				if(cur.random != null) {
					ans +="[" + cur.val + ".random-->" + Integer.toString(cur.random.val) + "] ";
				}
				cur = cur.next;
			}
			return ans;
		}
	}
	
	
	public node cloneMethod1(node head) {		// 时间复杂度 O(n) 空间复杂度(n)
		if(head == null) return null;
		node cur = head;
		HashMap<node, node> map = new HashMap<>();
		while(cur != null) {			// 克隆节点
			node new_node = new node(cur.val);
			map.put(cur, new_node);
			cur = cur.next;
		}
		cur = head;						// 串联节点
		while(cur != null) {
			node new_node = map.get(cur);
			if(cur.next != null) {
				new_node.next = map.get(cur.next);
			}
			if(cur.random != null) {
				new_node.random = map.get(cur.random);
			}
			cur = cur.next;
		}
		return map.get(head);
	}
	
	
	public node cloneMethod2(node head) {	// 时间复杂度 O(n) 空间复杂度(1)
		if(head == null) return null;
		node cur = head;
		while(cur != null) {	//克隆链表
			node new_node = new node(cur.val, cur.next);
			cur.next = new_node;				//将克隆节点接到原链表之后
			cur = new_node.next;
		}
		cur = head;
		while(cur != null) {	//设置random节点
			if(cur.random != null) {
				cur.next.random = cur.random.next;
			}
			cur = cur.next.next;
		}
		cur = head;					//拆分链表
		node dumpy = new node(0);	//哑结点 收集克隆节点
		node clone = dumpy;
		while(cur != null) {
			clone.next = cur.next;
			cur.next = cur.next.next;
			cur = cur.next;
			clone = clone.next;
		}
		return dumpy.next;
	}
	
	public static void main(String[] args) {
		node head = new RandomLinkClone().new node(0);
		head.insert(1).insert(2).insert(3).insert(4).insert(5).insert(6).insert(7).insert(8).insert(9);
		head.random = head.next.next.next;
		head.next.next.random = head;
		head.next.random = head.next.next.next.next.next.next;
		head.next.next.next.next.next.next.random = head.next.next.next.next.next.next.next;
		System.out.println("原     串:" + head);
		
		RandomLinkClone f = new RandomLinkClone();
		
		System.out.println("复制串1:" + f.cloneMethod1(head));
		System.out.println("原     串:" + head);
		System.out.println("复制串2:" + f.cloneMethod2(head));
		System.out.println("原     串:" + head);
		
	}
	
}

运行结果:
在这里插入图片描述

五、链表相交

给定两个可能有环也可能无环的单链表,链表头分别为head1,head2,如果相交请返回相交的第一个节点,如果不相交返回null。

判断有环还是无环

  1. HashSet 时间复杂度O(n) 空间复杂度O(n)
  2. 快慢指针 时间复杂度O(n) 空间复杂度O(1)
package LinkedList;

import java.util.HashSet;

import LinkedList.PatitionList.node;

public class HavingRing {
	
	public class node{
		int val;
		node next;
		
		public node(int val) {
			this.val = val;
			this.next = null;
		}
		
		public node(int val, node next) {
			this.val = this.val;
			this.next = next;
		}
		
		public node insert(int val) {
			node next = new node(val);
			node cur = this;
			while(cur.next != null) {
				cur = cur.next;
			}
			cur.next = next;
			return this;
		}
		
		public String toString() {
			String ans = "";
			node cur = this;
			HashSet<node> set = new HashSet<>();
			while(cur != null) {
				if(set.contains(cur)) {
					ans += "--> ";
					ans += Integer.toString(cur.val) + "成环";
					return ans;
				}else {
					set.add(cur);
					ans += Integer.toString(cur.val) + " ";
					cur = cur.next;
				}
			}
			return ans + "无环";
		}
	}
	
	public node hasRing1(node head) {	//有环,返回第一个入环节点,无环,返回null	时间复杂度O(n) 空间复杂度O(n)
		if(head == null) return null;
		HashSet<node> set = new HashSet<>();
		node cur = head;
		while(cur != null) {
			if(set.contains(cur)) {
				return cur;
			}else {
				set.add(cur);
			}
			cur = cur.next;
		}
		return null;
	}
	
	public node hasRing2(node head) {	//时间复杂度O(n) 空间复杂度O(1)
		if(head == null || head.next == null) return null;
		node fast = head;
		node slow = head;
		while(fast.next != null && fast.next.next != null) {
			slow = slow.next;
			fast = fast.next.next;
			if(slow == fast) {		//快慢指针相遇, 具体原因可以画图证明一下
				node cur = head;
				while(cur != slow) {
					cur = cur.next;
					slow = slow.next;
				}
				return slow;
			}
		}
		return null;
	}
	
	public static void main(String[] argv) {
		node head1 = new HavingRing().new node(0);
		head1.insert(1).insert(2).insert(3).insert(4).insert(5).insert(6).insert(7).insert(8).insert(9);
		node cur = head1;
		while(cur.next != null) {
			cur = cur.next;
		}
		cur.next = head1.next.next.next.next;
		System.out.println("有环串(head1):" + head1);
		
		node head2 = new HavingRing().new node(0);
		head2.insert(1).insert(2).insert(3).insert(4).insert(5).insert(6).insert(7).insert(8).insert(9);
		System.out.println("无环串(head2):" + head2);
		
		HavingRing f = new HavingRing();
		System.out.println("------------------方法一----------------");
		node f1 = f.hasRing1(head1);
		String ans = "";
		if(f1 == null) {
			ans = "无环";
		}else {
			ans = Integer.toString(f1.val);
		}
		System.out.println("head1入环点:" + ans);
		
		f1 = f.hasRing1(head2);
		if(f1 == null) {
			ans = "无环";
		}else {
			ans = Integer.toString(f1.val);
		}
		System.out.println("head2入环点:" + ans);
		System.out.println("------------------方法二----------------");
		node f2 = f.hasRing2(head1);
		ans = "";
		if(f2 == null) {
			ans = "无环";
		}else {
			ans = Integer.toString(f2.val);
		}
		System.out.println("head1入环点:" + ans);
		
		f2 = f.hasRing2(head2);
		if(f2 == null) {
			ans = "无环";
		}else {
			ans = Integer.toString(f2.val);
		}
		System.out.println("head2入环点:" + ans);
	}
}

运行结果
在这里插入图片描述

链表相交

  1. 两个链表均无环,第一种情况:尾结点不相同则不可能相交。第二种情况:尾结点相同,一定相交,对链表长度进行计数,得到两个链表长度的差额cnt,长链表先走cnt次,之后和短链表一起走,最后一定在相交节点相遇。
  2. 一个有环,一个无环,不可能相交
  3. 两个都有环,入环节点相同:则与第一种一定相交的情况类似,计数相遇,但是本次并不是计算链表的长度,只计算到入环节点的长度即可。入环节点不同:不一定相交,在环内从第一个链表的入环节点开始走,如果走了一圈没有遇到第二个链表的入环节点则一定不相交,否则相交,返回任意一个入环节点即可。
package LinkedList;

import java.util.HashSet;

import LinkedList.HavingRing.node;

public class Intersection {
	
	public class node{
		int val;
		node next;
		
		public node(int val) {
			this.val = val;
			this.next = null;
		}
		
		public node(int val, node next) {
			this.val = this.val;
			this.next = next;
		}
		
		public node insert(int val) {
			node next = new node(val);
			node cur = this;
			while(cur.next != null) {
				cur = cur.next;
			}
			cur.next = next;
			return this;
		}
		
		public String toString() {
			String ans = "";
			node cur = this;
			HashSet<node> set = new HashSet<>();
			while(cur != null) {
				if(set.contains(cur)) {
					ans += "--> ";
					ans += Integer.toString(cur.val) + "成环";
					return ans;
				}else {
					set.add(cur);
					ans += Integer.toString(cur.val) + " ";
					cur = cur.next;
				}
			}
			return ans + "无环";
		}
	}
	
	// 此代码写的较为冗余,不够美观,同时出口过多,读者可尝试进行简化。
	public node isIntersection(node head1, node head2) {
		node ring1 = hasRing(head1);
		node ring2 = hasRing(head2);
		// 两者都无环
		if(ring1 == null && ring2 == null) {
			node cur = head1;
			int cnt = 0;
			while(cur.next != null) {
				++cnt;
				cur = cur.next;
			}
			node e1 = cur;	// head1 的尾节点
			cur = head2;
			while(cur.next != null) {
				--cnt;
				cur = cur.next;
			}
			if(e1 != cur) {	//相交链表尾部必相等
				return null;
			}
			cur = cnt > 0? head1: head2;
			node cur_2 = cur == head1? head2: head1;
			cnt = Math.abs(cnt);
			for(int i=0; i<cnt; ++i) {
				cur = cur.next;
			}
			while(cur != cur_2) {
				cur = cur.next;
				cur_2 = cur_2.next;
			}
			return cur;
		}else if(ring1 != null && ring2 != null) {
			node cur = null;
			if(ring1 == ring2) {	//入环节点相同
				cur = head1;
				int cnt = 0;
				while(cur != ring1) {
					++cnt;
					cur = cur.next;
				}
				node e1 = cur;	// head1 的尾节点
				cur = head2;
				while(cur != ring2) {
					--cnt;
					cur = cur.next;
				}
				cur = cnt > 0? head1: head2;
				node cur_2 = cur == head1? head2: head1;
				cnt = Math.abs(cnt);
				for(int i=0; i<cnt; ++i) {
					cur = cur.next;
				}
				while(cur != cur_2) {
					cur = cur.next;
					cur_2 = cur_2.next;
				}
				return cur;
			}
			cur = ring1.next;
			while(cur != ring1) {
				if(cur == ring2) {	//相交
					return ring1;
				}
				cur = cur.next;
			}
			return null;
		}
		
		return null;		//一个有环一个无环不可能相交
	}
	
	public node hasRing(node head) {	
		if(head == null || head.next == null) return null;
		node fast = head;
		node slow = head;
		while(fast.next != null && fast.next.next != null) {
			slow = slow.next;
			fast = fast.next.next;
			if(slow == fast) {		//快慢指针相遇
				node cur = head;
				while(cur != slow) {
					cur = cur.next;
					slow = slow.next;
				}
				return slow;
			}
		}
		return null;
	}
	
	public static void main(String[] args) {
		node head1 = new Intersection().new node(0);
		head1.insert(1).insert(2).insert(3).insert(4).insert(5).insert(6).insert(7).insert(8).insert(9);
		
		node head2 = new Intersection().new node(10);
		head2.insert(11).insert(12).insert(13).insert(14).insert(15).insert(16).insert(17).insert(18).insert(19);
		node cur = head2;
		while(cur.next != null) {
			cur = cur.next;
		}
		cur.next = head1.next.next.next.next.next;
		
		Intersection f = new Intersection();
		System.out.println("-----------两个无环的相交串---------------------");
		System.out.println("串1:" + head1);
		System.out.println("串2:" + head2);
		node ans = f.isIntersection(head1, head2);
		if(ans != null) {
			System.out.println("相交于" + ans.val);
		}else {
			System.out.println("不相交");
		}
		
		cur.next = null;
		System.out.println("-----------两个无环的不相交串---------------------");
		System.out.println("串1:" + head1);
		System.out.println("串2:" + head2);
		ans = f.isIntersection(head1, head2);
		if(ans != null) {
			System.out.println("相交于" + ans.val);
		}else {
			System.out.println("不相交");
		}
		
		cur.next = head2.next.next.next;
		
		cur = head1;
		while(cur.next != null) {
			cur = cur.next;
		}
		cur.next = head2.next.next;
		
		System.out.println("-----------两个有环的相交串入环节点相同---------------------");
		System.out.println("串1:" + head1);
		System.out.println("串2:" + head2);
		ans = f.isIntersection(head1, head2);
		if(ans != null) {
			System.out.println("相交于" + ans.val);
		}else {
			System.out.println("不相交");
		}
		
		cur.next = head2.next.next.next.next.next;
		
		System.out.println("-----------两个有环的相交串入环节点不相同---------------------");
		System.out.println("串1:" + head1);
		System.out.println("串2:" + head2);
		ans = f.isIntersection(head1, head2);
		if(ans != null) {
			System.out.println("相交于" + ans.val);
		}else {
			System.out.println("不相交");
		}
		
		cur.next = head1.next.next.next;
		
		System.out.println("-----------两个有环的不相交串---------------------");
		System.out.println("串1:" + head1);
		System.out.println("串2:" + head2);
		ans = f.isIntersection(head1, head2);
		if(ans != null) {
			System.out.println("相交于" + ans.val);
		}else {
			System.out.println("不相交");
		}
		
		cur.next = null;
		System.out.println("-----------一个有环 一个无环的不相交串---------------------");
		System.out.println("串1:" + head1);
		System.out.println("串2:" + head2);
		ans = f.isIntersection(head1, head2);
		if(ans != null) {
			System.out.println("相交于" + ans.val);
		}else {
			System.out.println("不相交");
		}
	}
	
	
}

运行结果
在这里插入图片描述

六、删除节点(只给需要删除的节点不给头结点)

只给需要删除的节点是不可能做到将节点删除的,能做到的只是借尸还魂:就是将该节点后面的节点删除,同时将给定需要删除的节点的值更改成该节点后面节点的值,同时next指针指向下一个的下一个节点。但是该方法不能删除尾节点。

package LinkedList;

public class DeleteNode {
	public class node{
		int val;
		node next;
		
		public node(int val) {
			this.val = val;
			this.next = null;
		}
		
		public node(int val, node next) {
			this.val = this.val;
			this.next = next;
		}
		
		public node insert(int val) {
			node next = new node(val);
			node cur = this;
			while(cur.next != null) {
				cur = cur.next;
			}
			cur.next = next;
			return this;
		}
		
		public String toString() {
			String ans = "";
			node cur = this;
			while(cur != null) {
				ans += Integer.toString(cur.val) + " ";
				cur = cur.next;
			}
			return ans;
		}
	}
	
	public void deleteNode(node dn) {	//此方法无法物理删除头节点,所以头结点的地址不会变,不需要进行返回
		if(dn == null) {
			System.err.println("不能删除空节点");
			return;
		}
		node next = dn.next;
		if(dn.next == null) {
			System.err.println("无法删除尾节点");
		}else {
			dn.val = next.val;
			dn.next = next.next;
		}
	}
	
	public static void main(String[] args) {
		node head = new DeleteNode().new node(0);
		head.insert(1).insert(2).insert(3).insert(4).insert(5).insert(6).insert(7).insert(8).insert(9);
		
		node cur = head;
		while(cur.next != null) {
			cur = cur.next;
		}
		
		DeleteNode f = new DeleteNode();
		System.out.println("原串:" + head);
		f.deleteNode(head);
		System.out.println("删除头节点后:" + head);
		f.deleteNode(head.next.next.next);
		System.out.println("删除中间节点后:" + head);
		f.deleteNode(cur);
		System.out.println("删除尾节点后:" + head);
		f.deleteNode(null);
		System.out.println("删除空节点后:" + head);
	}
	
}

运行结果
在这里插入图片描述


总结

以上便是关于链表基础题的全部内容,前面的几道题都用了两种解法,解法的时间复杂度相同,不同点在于空间复杂度,请大家切记在笔试和面试中选择正确的方法,来为自己赢得加分。

1. 对于笔试,不用太在乎空间复杂度,一切为了时间复杂度
2. 对于面试,时间复杂度依然放在第一位,但是一定要找到空间最省的方法,给面试官留下更加深刻的印象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值