看过July的链表追赶问题后,想总结并且用java代码实现下:
问题1 : 求链表倒数第K个
class ListNode{
int data;
ListNode next;
public ListNode(){}
public ListNode(int data){
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public ListNode getNext() {
return next;
}
public void setNext(ListNode next) {
this.next = next;
}
}
ListNode head, p, q;
ListNode pOne, pTwo;
ListNode fun(ListNode head, int k){
pOne = pTwo = head;
for(;k>0 && pTwo!=null;k--){
pTwo = pTwo.next;
}
if(k>0) return null;
while(pTwo!=null){
pOne = pOne.next;
pTwo = pTwo.next;
}
return pOne;
}
问题2 : 编程判断两个链表是否相交
思路和大部分文字都是从July的博客上面来的:
1. 暴力破解直接遍历,额
2. 相交了就代表有相同的节点,判断相同,应该想到hash,用空间换取时间。
针对第一个链表以内存地址为内容构造hash表,遍历第二个链表,如果能找到,说明有相同节点,时间复杂度O(length(h1)+length(h2)),但是牺牲了空间。
由于空间花费太大,所以个人觉得第2点一般是没有太大用处
3. 如果两个没有环的节点相交与某一节点,这个节点之后的所有节点都是两个链表共有的,所以只要判断两个链表的尾指针是否相等。时间复杂度与上面一样,但是空间是O(1)
由于解法3是面对无环,有环的时候怎么办?详情参见July的博客,这里只是贴出自己的java实现的地方:
判断是否有环,同时生成环中的一点,也就是相遇点,如果无环,生成链表的尾指针。
static boolean isCircle(ListNode head, ListNodeClass LNC){
ListNode fast = head.getNext();
ListNode slow = head;
// 暂时不知道是否有环,如果无环,fast和slow有一个会走到尾节点
// 如果有环 fast和slow会相遇,所以两种情况他们都会跳出循环
while(fast!=slow && fast.hasNext() && slow.hasNext()){
if(fast.hasNext()){
// fast先前进一步
fast = fast.getNext();
}
// 这个时候fast的next是null
if(!fast.hasNext()){
// 得到了尾指针
LNC.lastNode = fast;
}
// 一般情况下应该是fast比slow更快到达尾
if(!slow.hasNext()){
LNC.lastNode = slow;
}
if(fast.hasNext())
fast=fast.getNext();
if(slow.hasNext())
slow = slow.getNext();
}
// fast slow 不是尾节点(环也没有尾节点)而且他们相遇了~~~
if( fast==slow && fast.hasNext() && slow.hasNext()){
LNC.circleNode = fast;//相遇点
return true;
}
else{
return false;//到达了尾节点,无环
}
}
class ListNodeClass{
public ListNode circleNode = null;
public ListNode lastNode =null;
}
接下来是 综合判断代码:
boolean detect(ListNode head1 , ListNode head2){
ListNodeClass LNC1 = new ListNodeClass();
ListNodeClass LNC2 = new ListNodeClass();
boolean isCircle1 = isCircle(head1,LNC1);
boolean isCircle2 = isCircle(head2,LNC2);
System.out.println("isCircle1: "+isCircle1);
System.out.println("isCircle2: "+isCircle2);
if(isCircle1!=isCircle2)
return false;
else if(!isCircle1 && !isCircle2)
// 无环 ,比较尾节点
return LNC1.lastNode == LNC2.lastNode;
else{
//判断同一个,两个带环链表是同一个链表
if(LNC1.circleNode == LNC2.circleNode)
return true;
// 从其中一个相遇点出发
ListNode tempNode = LNC1.circleNode.getNext();
// 跳出循环条件是 走了一圈
while(tempNode != LNC1.circleNode){
//碰到了 circleNode2就是说在环内
System.out.println("碰到了 circleNode2就是说在环内");
if(tempNode == LNC2.circleNode)
{
System.out.println("tempNode == LNC2.circleNode");
return true;
}
tempNode = tempNode.getNext();
}
return false;
}
}
全部的JAVA代码:
public class myLinkedList {
public static void main(String[] args) {
int[] arr = new int[]{1,2,3,4,5,6,7,8,9,10};
myLinkedList myLinkedListObj = new myLinkedList();
ListNode headNode = myLinkedListObj.buildList(arr);
ListNode headCirNode = myLinkedListObj.buildCirList(arr,arr.length/2);
ListNode tempNode = headCirNode;
ListNode temp=null;
System.out.println(myLinkedListObj.detect(headCirNode, headCirNode));
System.out.println(myLinkedListObj.fun(headNode, 3).getData());
}
// 构造无环链表
ListNode buildList(int[] arr){
ListNode first = new ListNode();
ListNode pNode = first;
for(int da : arr){
ListNode node = new ListNode(da);
pNode.setNext(node);
pNode = node;
}
return first;
}
// 构造有环链表
ListNode buildCirList(int[] arr,int cir){
int lengthOfArr = arr.length;
int beginCir = cir;
ListNode first = new ListNode();
ListNode pNode = first;
ListNode pNodeCir;
for(int i=0;i<beginCir;i++){
ListNode node = new ListNode(arr[i]);
pNode.setNext(node);
pNode = node;
}
// 此时的pNode是环首
pNodeCir = pNode;
for(int i=beginCir;i<lengthOfArr;i++){
ListNode node = new ListNode(arr[i]);
pNode.setNext(node);
node.setNext(pNodeCir);
pNode = node;
}
return first;
}
class ListNode{
int data;
ListNode next;
public ListNode(){}
public ListNode(int data){
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public ListNode getNext() {
return next;
}
public void setNext(ListNode next) {
this.next = next;
}
public boolean hasNext(){
return next==null?false:true;
}
}
// ListNode head, p, q;
ListNode pOne, pTwo;
ListNode fun(ListNode head, int k){
pOne = pTwo = head;
for(;k>0 && pTwo!=null;k--){
pTwo = pTwo.next;
}
if(k>0) return null;
while(pTwo!=null){
pOne = pOne.next;
pTwo = pTwo.next;
}
return pOne;
}
static boolean isCircle(ListNode head, ListNodeClass LNC){
ListNode fast = head.getNext();
ListNode slow = head;
// 暂时不知道是否有环,如果无环,fast和slow有一个会走到尾节点
// 如果有环 fast和slow会相遇,所以两种情况他们都会跳出循环
while(fast!=slow && fast.hasNext() && slow.hasNext()){
if(fast.hasNext()){
// fast先前进一步
fast = fast.getNext();
}
// 这个时候fast的next是null
if(!fast.hasNext()){
// 得到了尾指针
LNC.lastNode = fast;
}
// 一般情况下应该是fast比slow更快到达尾
if(!slow.hasNext()){
LNC.lastNode = slow;
}
if(fast.hasNext())
fast=fast.getNext();
if(slow.hasNext())
slow = slow.getNext();
}
// fast slow 不是尾节点(环也没有尾节点)而且他们相遇了~~~
if( fast==slow && fast.hasNext() && slow.hasNext()){
LNC.circleNode = fast;//相遇点
return true;
}
else{
return false;//到达了尾节点,无环
}
}
class ListNodeClass{
public ListNode circleNode = null;
public ListNode lastNode =null;
}
boolean detect(ListNode head1 , ListNode head2){
ListNodeClass LNC1 = new ListNodeClass();
ListNodeClass LNC2 = new ListNodeClass();
boolean isCircle1 = isCircle(head1,LNC1);
boolean isCircle2 = isCircle(head2,LNC2);
System.out.println("isCircle1: "+isCircle1);
System.out.println("isCircle2: "+isCircle2);
if(isCircle1!=isCircle2)
return false;
else if(!isCircle1 && !isCircle2)
// 无环 ,比较尾节点
return LNC1.lastNode == LNC2.lastNode;
else{
//判断同一个,两个带环链表是同一个链表
if(LNC1.circleNode == LNC2.circleNode)
return true;
// 从其中一个相遇点出发
ListNode tempNode = LNC1.circleNode.getNext();
// 跳出循环条件是 走了一圈
while(tempNode != LNC1.circleNode){
//碰到了 circleNode2就是说在环内
System.out.println("碰到了 circleNode2就是说在环内");
if(tempNode == LNC2.circleNode)
{
System.out.println("tempNode == LNC2.circleNode");
return true;
}
tempNode = tempNode.getNext();
}
return false;
}
}
}
寻找两链表相交的第一个点,这部分已经时间看了,mark一个
找到环的入口,这博文写得不错的。
本次学习毕。