《慕课网玩转算法面试》笔记及习题解答5.1.~5.3

来源:互联网 发布:c语言标准库函数 手册 编辑:程序博客网 时间:2024/06/05 09:29

链表问题

处理链表的问题,我们通常可以多设立指针来保存信息


LeetCode 206 翻转链表

思路:使用三个指针分别指向当前节点和前后节点, 改变链表的链接方向并右移,注意终止条件和终止时指向头节点的指针应该为pre, cur已经为指向头节点之后的NULL指针

    ListNode* reverseList(ListNode* head) {        ListNode* pre = NULL;        ListNode* cur = head;        while( cur != NULL )        {            ListNode* next = cur->next;            cur->next = pre;            pre = cur;            cur = next;        }        return pre;    }





练习题:

LeetCode 92

Reverse a linked list from position m to n. Do it in-place and in one-pass.

思路:设置一个虚拟头节点避免头节点的判断操作,先将指针移动到变动区域的前一个节点,使用头插法修改区域内的节点顺序

    ListNode* reverseBetween(ListNode* head, int m, int n) {          ListNode* dummyHead = new ListNode(-1);        dummyHead->next = head;        ListNode* pre = dummyHead;        for(int i = 0; i < m-1; i++)            pre = pre->next;        ListNode* cur = pre->next;        for(int i = 0; i < n-m; i++){            ListNode* nextNode = cur->next;            cur->next = nextNode->next;            nextNode->next = pre->next;            pre->next = nextNode;                    }        ListNode *delNode = dummyHead;        ListNode* returnNode = dummyHead->next;        delete delNode;        return returnNode;    }



LeetCode 83

Given a sorted linked list, delete all duplicates such that each element appear only once.

For example,
Given 1->1->2, return 1->2.
Given 1->1->2->3->3, return 1->2->3.

思路:遍历,没啥别的

    ListNode* deleteDuplicates(ListNode* head) {        ListNode* dummyHead = new ListNode(-1);        dummyHead->next = head;        ListNode* curNode = head;        while(curNode && curNode->next){            if(curNode->val == curNode->next->val){                ListNode* delNode = curNode->next;                curNode->next = curNode->next->next;                delete delNode;            }else{                curNode = curNode->next;            }        }        ListNode* resNode = dummyHead->next;        delete dummyHead;        return resNode;    }



LeetCode 86

Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.

You should preserve the original relative order of the nodes in each of the two partitions.

思路:头插法,注意此时的“头”应该是从左往右第一个大于x的点的左侧。比如1->4->3->2->5->2 ,那么“头”就是应该是1,然后以4为cur节点向右移动,每次碰到小于x的点就插在“头”后面,并移动“头”到4的前面。

    ListNode* partition(ListNode* head, int x) {        ListNode* dummyHead = new ListNode(-1);        dummyHead->next = head;                ListNode* pre = dummyHead;        while(pre->next && pre->next->val < x)            pre = pre->next;        ListNode* cur = pre->next;        while(cur && cur->next){            if(cur->next->val < x){                ListNode* moveNode = cur->next;                cur->next = moveNode->next;                moveNode->next = pre->next;                pre->next = moveNode;                pre = pre->next;            }            else                cur = cur->next;        }        ListNode* resNode = dummyHead->next;        delete dummyHead;        return resNode;    }

LeetCode 328

Given a singly linked list, group all odd nodes together followed by the even nodes. Please note here we are talking about the node number and not the value in the nodes.

You should try to do it in place. The program should run in O(1) space complexity and O(nodes) time complexity.

Example:
Given 1->2->3->4->5->NULL,
return 1->3->5->2->4->NULL.

思路:奇偶两个指针遍历,注意结束时的条件

    ListNode* oddEvenList(ListNode* head) {        if(head == NULL || head->next == NULL)            return head;        ListNode* even_head = head->next;        ListNode* odd = head;        ListNode* even = even_head;        while(even && odd && even->next && odd->next)        {            odd->next = even->next;            even->next = odd->next->next;            odd = odd->next;            even = even->next;        }        odd->next = even_head;                return head;    }



LeetCode 2

思路:遍历两个链表,注意进位,遍历完链表后需要判断最后一个位是否有进位

    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {        ListNode* dummyHead = new ListNode(-1);        ListNode* cur = dummyHead;        int nextBit = 0;        while(l1  && l2){            int sum = l1->val + l2->val + nextBit;            nextBit = sum / 10;            sum %= 10;            cur->next = new ListNode(sum);            cur = cur->next;            l1 = l1->next;            l2 = l2->next;        }        while(l1){            int sum = l1->val + nextBit;            nextBit = sum / 10;            sum %= 10;            cur->next = new ListNode(sum);            cur = cur->next;            l1 = l1->next;        }        while(l2){            int sum = l2->val + nextBit;            nextBit = sum / 10;            sum %= 10;            cur->next = new ListNode(sum);            cur = cur->next;            l2 = l2->next;        }          if(nextBit)            cur->next = new ListNode(nextBit);        return dummyHead->next;    }


LeetCode 445

思路:和LeetCode 2差不多,还是要注意进位,因为是倒序,可以考虑用两次stack,其实用stack+头插法也可以,这里就贴个stack+头插法(两次stack的提交被覆盖了找不到= =)


    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {        stack<int> s1,s2;        while(l1){            s1.push(l1->val);            l1 = l1->next;        }        while(l2){            s2.push(l2->val);            l2 = l2->next;        }        int nextBit = 0;        ListNode* newHead = new ListNode(-1);        while(!s1.empty() && !s2.empty())        {            int sum = s1.top() + s2.top() + nextBit;            nextBit = sum / 10;            sum %= 10;                    ListNode* newNode = new ListNode(sum);            newNode->next = newHead->next;            newHead->next = newNode;            s1.pop();            s2.pop();        }        while(!s1.empty()){            int sum = s1.top() + nextBit;            nextBit = sum / 10;            sum %= 10;            ListNode* newNode = new ListNode(sum);            newNode->next = newHead->next;            newHead->next = newNode;            s1.pop();        }        while(!s2.empty()){            int sum = s2.top() + nextBit;            nextBit = sum / 10;            sum %= 10;            ListNode* newNode = new ListNode(sum);            newNode->next = newHead->next;            newHead->next = newNode;            s2.pop();        }        if(nextBit != 0){                       ListNode* newNode = new ListNode(nextBit);            newNode->next = newHead->next;            newHead->next = newNode;        }        return newHead->next;    }


LeetCode 203

思路:简历一个虚拟的头节点可以简化逻辑,每次访问当前节点的next节点判断

    ListNode* removeElements(ListNode* head, int val) {        ListNode* dummyHead = new ListNode(-1);        dummyHead->next = head;        ListNode* curNode = dummyHead;        while(curNode->next)        {            if(curNode->next->val == val){                ListNode* delNode = curNode->next;                curNode->next = curNode->next->next;                delete delNode;            }            else{                curNode = curNode->next;            }        }        ListNode* returnNode = dummyHead->next;        delete dummyHead;        return returnNode;            }



练习题

LeetCode 82

思路:扫描两次,第一次用哈希表记录每个数字的次数,第二次删除次数大于1的节点,如果只遍历一次,也可以考虑用两个指针前后遍历,不过我没实现,感觉应该可行

    ListNode* deleteDuplicates(ListNode* head) {        unordered_map<int,int> record;        ListNode* cur = head;        while(cur)        {            record[cur->val]++;            cur = cur->next;        }        ListNode* dummyHead = new ListNode(-1);        dummyHead->next = head;        ListNode* curNode = dummyHead;        while(curNode->next)        {            if( record[curNode->next->val] > 1 )            {                ListNode * delNode = curNode->next;                curNode->next = curNode->next->next;                delete delNode;            }            else{                curNode = curNode->next;            }                                     }        ListNode *resNode =  dummyHead->next;        delete dummyHead;        return resNode;    }



LeetCode 21

思路:两个指针遍历,注意节点移动时的先后顺序即可,最好画个图

    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {        ListNode* dummyHead1 = new ListNode(-1);        dummyHead1->next = l1;        ListNode* dummyHead2 = new ListNode(-1);        dummyHead2->next = l2;              ListNode* curNode1 = dummyHead1;        ListNode* curNode2 = dummyHead2;        while(curNode1->next && curNode2->next){ //两个指针遍历两个链表            if(curNode1->next->val <= curNode2->next->val ) //l1的当前节点较小则直接移动                curNode1 = curNode1->next;            else{//l2的当前节点较小则直接移动到l1的当前节点之前,注意前后顺序,最好画图                ListNode *moveNode = curNode2->next;                curNode2->next = moveNode->next;                moveNode->next = curNode1->next;                curNode1->next = moveNode;                curNode1 = curNode1->next;            }        }        while(curNode2->next)  //当l2还有节点时,做同样操作,l1还有则无所谓        {            ListNode *moveNode = curNode2->next;            curNode2->next = moveNode->next;            moveNode->next = curNode1->next;            curNode1->next = moveNode;            curNode1 = curNode1->next;                        }        ListNode *resNode = dummyHead1->next;        delete dummyHead1;        delete dummyHead2;        return resNode;    }



阅读全文
0 0
原创粉丝点击