做题后觉得,这些算法都不算编程语言层面东西了,这和数学更为接近,我讨厌数学!虽然由思路转为代码是代码能力没错,但更关键的思路还是偏向数学层面的求解。

一. 判断是否为回文单链表

从首结点看和从末尾结点看整个链表是一样的就是回文。

a. 想到的思路:把值放数组里比呗

1)快慢指针定位中点;
2)从中点向后取值放入一个数组中;
3)反向比较数组与慢指针继续走的值;
4)一样就是回文链表,不一样就不是。

遇到的问题:要分奇偶,先判断奇偶

链表为偶数,思路没问题。为奇数,是必出错的。
解决方法:偶数正常比,奇数中间自己和自己比。

个人思路的缺陷

1)链表扯上数组就是愚笨的,即转为地址空间连续的数据处理。
2)那你数组开多大的呢?题目要是没说明呢?(这里是C语言本身的缺陷,C++就是不必固定数组空间大小,希望我没有说错)

代码

bool isPalindrome(struct ListNode* head) {
    int arr[100000] = { 0 };
    Node* fast = head;
    Node* slow = head;
    int i = 1;
    int odd = 0;
    arr[0] = head->val;
    while (fast)
    {
        fast = fast->next;
        if (fast == NULL)奇数跳出现NULL说明为奇数
            odd = 1;

        if (fast)
            fast = fast->next;

        if (fast)
        {
            slow = slow->next;
            arr[i] = slow->val;
            i++;
        }


    }
    int num = 0;

    if (i > 1) 
        num = i;
    else
    {
        num = 1;
    }

    if (slow->next == NULL)只有一个元素的考虑
        return true;

    if (odd == 0)奇数不动,偶数进一位
    {
        slow = slow->next;
    }
    
    for (i = 0; i < num; i++)
    {
        if (arr[num - i - 1] != slow->val)
        {
            return false;
        }
        if (slow)
            slow = slow->next;

    }
    return true;

}

b. 参考思路

1)快慢指针定位一半;
2)翻转后面的链表;(不必考虑数组开辟多少空间)
3)比较两个链表是否一样。

增益点:链表问题尽量不涉及数组

上面也写到了。

代码

typedef struct ListNode Node;
bool isPalindrome(struct ListNode* head){
    
    Node* fast=head;
    Node* slow=head;
    Node* storeslow=NULL;

    while(fast)    中点
    {
        fast=fast->next;
        if(fast)
        fast=fast->next;
        storeslow=slow;
        slow=slow->next;
    }
    storeslow->next=NULL;

    Node* n1=NULL;
    Node* n2=slow;
    Node* n3=NULL;

    while(n2) 翻转链表
    {
        if(n2->next)
        n3=n2->next;

        n2->next=n1;

        n1=n2;
        n2=n3;
        if(n3)
        n3=n3->next;
    }
    while(n1&&head)比较两个链表
    {
        if(n1->val!=head->val)
        return false;

        n1=n1->next;
        head=head->next;
    }
    return true;
}

二. 判断两个链表是否相交

a. 想到的思路:*->next一样不就相交了吗?

1)headA遍历的同时,遍历headB;
2)出现相等的地址就相交了;
3)一方结束到NULL,就没相交。

缺陷:复杂度

1)O(N^2)

看参考思路的疑惑

双指针必须要互相有数量关系才能用,我都不知道A,B的长度,我怎么用双指针?

代码

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
   if(headA==NULL||headB==NULL)
   return NULL;
    
   struct ListNode * storeB=headB;
    while(headA)
    {
        headB=storeB;
  		while(headB)
    	{
    
        	if(headA==headB)
        	{
            	return headA;
        	}
        	else
        	{
            	headB=headB->next;
        	}
       }
       headA=headA->next;
       }
    return NULL; 
}

b. 参考思路

1)求headA长度,求haedB长度;
2)长度相减;
3)让长的一方先走那么多步,双指针定位。

增益点一:没有数量关系,你不会自己创造出来吗????

你都疑惑不等长怎么在遍历的同时,判断是否相交,你就自己创造让二者同步。
你的快慢指针的二倍速不也是自己创造出来的?怎么到这就忘了创造?

增益点二:链表长度真的像之前想的那样没意义吗?

别那么死板,要用长度,就求。

代码

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
   if(headA==NULL||headB==NULL)
   return NULL;
    struct ListNode * storeA=headA;
   struct ListNode * storeB=headB;
   int lA=0;
   int lB=0;
   int L=0;
    while(storeA->next)
    {
        storeA=storeA->next;
        lA++;
    }
    while(storeB->next)
    {
        storeB=storeB->next;
        lB++;
    }
    
    if(lA>=lB)
    {
        L=lA-lB    /A先走
        while(L--)
        {
            if(headA)
            headA=headA->next;
        }
    }
    else
    {
        L=lB-lA;    /B先走
        while(L--)
        {
            if(headB)
            headB=headB->next;
        }
    }
        while(headA)        /等长
        {
            if(headA==headB)
            return headA;
            headA=headA->next;
            headB=headB->next;
        }
        return NULL;

}
02-05 06:34