2-bis problem list pointer LeetCode--

2-bis problem list pointer LeetCode--

Thinking:
to determine whether there is a chain ring
cited several situations:

graph LR
A-->B
B-->C
C-->D
D-->E
E-->C
graph LR
A-->B
B-->A

You may have proposed a solution using a hash table. However, there is a more efficient solution using two-hand technique. Before you read what follows, try to think about myself.

Imagine there are two different speeds runners. If they are traveling on a straight road, run by the first destination. However, if they are running on a circular track, then sprint to catch up with those who will be if it continues running jogger.

This is what we use in the list two different speeds pointers situation encountered when:

如果没有环,快指针将停在链表的末尾。
如果有环,快指针最终将与慢指针相遇。

So the remaining question is:

这两个指针的适当速度应该是多少?

A secure option is to slowly move the pointer one step each time, the pointer moves fast two steps. Each iteration, the pointer will quickly move additional step. If the length of the loop is M, after M iterations, fast pointer certainly be looped once, and slow to catch up with the pointer.

那其他选择呢?它们有用吗?它们会更高效吗?

1 1 title circular linked list (simple)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        // 当链表中没有节点或只有一个节点时 false
        if(!head || !head->next)
            return false;
        // 两个节点的初始值都是head
        ListNode* p1 = head;
        ListNode* p2 = head;
        // 
        while( p1->next && p2->next)
        {
            if(p1->next == p2->next->next)
                return true;
            p1 = p1->next;
            p2 = p2->next->next;
            if( !p1 || !p2 )
                return false;
        }
        return false;
    }
};

Question 2 circular linked list 2 (medium title)

Own ideas:
barabara
but
their ideas ... not to
look at other people's good ideas

graph LR
0-->1
1-->2
2-->3
3-->4
4-->5
5-->2

This question is on offer ideas to prove safety, mainly the use of double-pointer, different starting points.
The number of nodes arranged within the ring is n, then a 0 from the node, the other from the n + 1 nodes.
Meet at the entrance is.
It means encounter problems with a ring.

This question therefore needs to solve several problems

  1. Are you sure you have the ring list
  2. Determining the number of list node
  3. Determining the ingress node
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        int num = counter(head);
        if ( num == 0)
            return NULL;
        ListNode* pa = head;
        ListNode* pb = head;
        for (int i = 0 ; i < num; i++)
        {
            pb = pb->next;
        }
        while (pa->next && pa->next)
        {
            if(pa == pb)
                return pb;
            pa = pa->next;
            pb = pb->next;
        }
        return NULL;
    }
    
    int counter( ListNode* head )
    {
        // 链表为空或链表中只有一个节点-->不存在环-返回0
        if( !head || !head->next )
            return 0;
        // 设置双指针
        ListNode* p1 = head;
        ListNode* p2 = head;
        // 
        int count = 0;
        while( p1->next && p2->next )
        {
            // 若p1和P2即将相遇,重新赋值,并开始计数
            if( p1->next == p2->next->next)
            {
                p1 = p1->next;
                p2 = p1->next;
                count = 2;
                while(p2->next)
                {
                    if( p1 == p2 )
                    {
                        return count;
                    }
                    p2 = p2->next;
                    count ++;
                }
            }
            p1 = p1->next ;
            p2 = p2->next->next;
            if(!p1||!p2)
                return 0;
        }
        return 0;
    }
};

Exceeds the time limit -
to modify the following code, passed the test;

Modify the content:
  1. While avoiding double loop
  2. While avoiding the loop termination condition is true value
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        // 确定快慢指针相遇的节点
        ListNode* pmeet = meeting(head);
        if ( pmeet == NULL)
            return NULL;
        // 确定环内节点的个数
        int count = 1 ;
        ListNode* p1 = pmeet;
        while( p1->next != pmeet )
        {
            p1 = p1->next;
            count ++;
        }
        // 确定环的入口节点
        ListNode* pa = head;
        ListNode* pb = head;
        for (int i = 0 ; i < count; i++)
        {
            pb = pb->next;
        }
        while ( pa != pb )
        {
            pa = pa->next;
            pb = pb->next;
        }
        return pa;
    }
    
    // 确定快慢指针相遇的节点
    ListNode* meeting (ListNode* head )
    {
        // 链表为空或链表中只有一个节点-->不存在环-返回0
        if( !head || !head->next )
            return NULL;
        // 设置双指针
        ListNode* p1 = head;
        ListNode* p2 = head;
        // 
        ListNode* meet = head;
        while( p1->next && p2->next )
        {
            // 若p1和P2即将相遇,重新赋值,并开始计数
            if( p1->next == p2->next->next)
            {
                meet = p1->next;
                return meet;
            }
            p1 = p1->next ;
            p2 = p2->next->next;
            if(!p1||!p2)
                return NULL;
        }
        return NULL;
    }
};

Problem 3 intersect list

graph LR
A-->B
B-->C
C-->F
E-->F
D-->E
F-->G
G-->H
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        // 如果两个链表其中任意一个为空就不会有相交节点
        if( !headA || !headB )
            return NULL;
        // 两个链表从头节点就相交了
        if( headA == headB )
            return headA;
        ListNode* pa = headA;
        ListNode* pb = headB;
        // 求两个链表的长度
        int numa = counter(headA);
        int numb = counter(headB);
        // 哪一个链表长,其指针就往前步进长度差的步长
        int step = 0;
        if ( numa >= numb )
        {
            step = numa - numb;
            for(int i = 0; i < step ; ++i)
            {
                pa = pa->next;        
            }
        }
        else
        {
            step = numb - numa;
            for(int j = 0 ; j < step; ++j)
            {
                pb = pb->next;
            }
        }
        
        // 定位第一个相同的节点
        while ( pa && pb &&  (pa != pb) )
        {
            pa = pa->next;
            pb = pb->next;
        }
        return pb;
        
        // 第二种循环的写法
        /*
        while ( pa && pb )
        {
            if ( pa == pb )
                return pa;
            pa = pa->next;
            pb = pb->next;
        }
        return NULL;
        */
    }
    // 返回单链表中的节点数
    int counter(ListNode* head)
    {
        ListNode* p = head;
        int count = 1;
        if( !p )
            return 0;
        if( !p->next )
            return 1;
        while( p->next )
        {
            p = p->next;
            ++count;
        }
        return count;
    }
};

4 questions delete the list of the penultimate node n

The first idea is solved by the auxiliary stack

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // 
        if( !head || n <= 0 )
            return NULL;
        // 建立一个辅助栈
        stack<ListNode*> nodes;
        // 遍历链表,依次放入栈中
        ListNode* p = head;
        while(p)
        {
            nodes.push(p);
            p = p->next;
        }
        
        if(n == 1)
        {
            nodes.pop();
            ListNode* pend = nodes.top();
            pend->next = nullptr;
            return head;
        }
        // 遍历栈中的节点到第n-1个节点
        int i = 1;
        while ( i != n-1 && n > 1 )
        {
            if(nodes.empty())
                return NULL;
            nodes.pop();
            ++i;
        }
        ListNode* pe = nodes.top();
        nodes.pop();
        nodes.pop();
        ListNode* ps = nodes.top();
        ps->next = pe;
        return head;
    }
};

Test cases through, but submitted answers to an error

Line 152: Char 17: runtime error: reference binding to misaligned address 0xbebebebebebec0b6 for type 'struct ListNode *', which requires 8 byte alignment (stl_deque.h)

Code is modified as follows:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // 
        if( !head || n <= 0 )
            return NULL;
        // 建立一个辅助栈
        stack<ListNode*> nodes;
        // 遍历链表,依次放入栈中
        ListNode* p = head;
        while(p)
        {
            nodes.push(p);
            p = p->next;
        }
        // 倒数第1个节点
        if(n == 1)
        {
            nodes.pop();
            if(nodes.empty())
                return NULL;
            ListNode* pend = nodes.top();
            pend->next = NULL;
            return head;
        }
        // 倒数n-1个节点之前的节点出栈
        int i = 1;
        while ( i != n-1 && n >= 2 )
        {
            if(nodes.empty())
                return NULL;
            nodes.pop();
            ++i;
        }
        // 得到第n-1个节点,使其出栈
        ListNode* pe = nodes.top();
        nodes.pop();
        // 第n个节点出栈
        nodes.pop();
        // 如果倒数第n个节点之前再无节点,head = pe
        if(nodes.empty())
        {
            head = pe;
            return head;
        }
        ListNode* ps = nodes.top();
        ps->next = pe;
        return head;
    }
};

When using the auxiliary stack, the robustness of the code should pay great attention to
the stack, the stack is empty if we must pay attention! ! !

Summary - Double pointer to the list of issues

Code templates:

// Initialize slow & fast pointers
ListNode* slow = head;
ListNode* fast = head;
/**
 * Change this condition to fit specific problem.
 * Attention: remember to avoid null-pointer error
 **/
while (slow && fast && fast->next) {
    slow = slow->next;          // move slow pointer one step each time
    fast = fast->next->next;    // move fast pointer two steps each time
    if (slow == fast) {         // change this condition to fit specific problem
        return true;
    }
}
return false;   // change return value to fit specific problem

prompt

It is similar to us in the array learned content. But it may be more difficult and more error-prone. You should note the following:

  1. Before calling the next field, always check whether a node is empty.
    Get the next node in the empty node will cause a null pointer errors. For example, before we run fast = fast.next.next, need to check the fast and fast.next not empty.

  2. Carefully define the conditions for the end of the cycle . Run a few examples to make sure your condition does not cause an infinite loop end. When you define the end condition, you have to consider our first hint.

Complexity Analysis

Space complex analysis easy. If you only use the pointer without using any additional space, so the space complexity is O (1). However, the complexity of the analysis time is more difficult. To get the answer, we need the number of operating cycles of analysis.

In the foregoing exemplary lookup cycle, we assumed that each pointer moves fast 2-step, each of the slower moving the pointer one step.

如果没有循环,快指针需要 N/2 次才能到达链表的末尾,其中 N 是链表的长度。
如果存在循环,则快指针需要 M 次才能赶上慢指针,其中 M 是列表中循环的长度。

Obviously, M <= N. So we will run the loop N times. For each cycle, we only need constant level of time. Thus, the time complexity of the algorithm is a total of O (N).

Own analysis of other issues to improve analytical skills. Do not forget to take into account different conditions. If it is difficult to analyze all cases, please consider the worst case.

Guess you like

Origin www.cnblogs.com/jiangxinyu1/p/12285012.html