从今天开始要攻克算法专题了,今天是链表篇,关于链表相关的考题,不会太多涉及时间复杂度,而主要考察链表和指针操做;为啥大厂喜欢考察数据结构和算法?由于这些是对基本功的升华,不会考察数组指针、函数指针等,考一个链表,就能考察对指针的理解,我相信不理解指针,链表学起来很费劲!ios
我会一个模块一个模块进行学习和练习,练习时我会从leetcode上选题,都知道leetcode吧?是OJ中最权威的平台了,在上面能够找算法题和练习,很好的一个网站,每个题都会说明leetcode的第几题,方便你们查找和练习。web
LeetCode上第206题:Reverse Linked List,官网是英文,但鉴于英文对一些人看起来比较费劲,翻译成中文,以下:算法
反转单链表。 例子: 输入:1 - > 2 - > 3 - > 4 - > 5 - > NULL 输出:5 - > 4 - > 3 - > 2 - > 1 - > NULL 跟进: 链表能够迭代或递归地反转。你能实现这两个吗?
可能有人会想到直接去改链表节点里的值,这是不容许,通常都是操做next指针,去改变指针指向;画图进行讲解,以下:数组
须要三个指针pre/cur/next去反转,将2位置指向pre位置,pre指向1号位置,1号位置指向3号位置,这样就能够进行反转了。代码以下:数据结构
struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; // 206. Reverse Linked List // https://leetcode.com/problems/reverse-linked-list/description/ // 时间复杂度: O(n) // 空间复杂度: O(1) class Solution { public: 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的格式进行编写的,而后去LeetCode上去试一下,鉴于可能有人不知道怎么使用LeetCode,我简单进行演示一下怎么使用:数据结构和算法
第一步:百度leetcode,以下:ide
第二步:点击“Create Account”,建立本身的用户,须要填写邮箱,须要点击连接进行激活,不然刷题没法提交;刚开始写的邮箱没给我发邮件,又在我的资料里从新换了邮箱,就能够收到了;函数
第三步:在首页找题,若是能记住题目,能够输入题目进行搜索;也能够搜索题号,如206,也能够搜索到,以下图:学习
第四步:提交代码,我将上面写的代码放到leetcode,点击右下角的“Submit Solution”,就能够看到下面的“Submission Solution:Accepted”,就表示经过了,以下图:测试
这样就OK了。
这部分主要说明一下怎么去本身测试程序的运行?主要实现链表的建立、遍历、销毁(C++堆上内存要本身管理)。
将数组传给函数,根据数组实现链表赋值;还会传入n建立多大的链表,代码以下:
// 根据n个元素的数组arr建立一个链表, 并返回链表的头 ListNode* createLinkedList(int arr[], int n){ if(n == 0) return NULL; ListNode* head = new ListNode(arr[0]); ListNode* curNode = head; for(int i = 1 ; i < n ; i ++){ curNode->next = new ListNode(arr[i]); curNode = curNode->next; } return head; }
注意:建立的链表,没有真实的“头结点”,就是只存一个开始指针的节点,因此删除第一个节点要注意!
经过头结点进行遍历链表,代码以下:
// 打印以head为头结点的链表信息内容 void printLinkedList(ListNode* head){ ListNode* curNode = head; while(curNode != NULL){ cout << curNode->val << " -> "; curNode = curNode->next; } cout << "NULL" << endl; return; }
将建立时分配的内存释放,代码以下:
// 释放以head为头结点的链表空间 void deleteLinkedList(ListNode* head){ ListNode* curNode = head; while(curNode != NULL){ ListNode* delNode = curNode; curNode = curNode->next; delete delNode; } return; }
对反转链表代码进行测试,总体代码以下:
#include <iostream> using namespace std; /** * Definition for singly-linked list. */ struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; /// LinkedList 测试辅助函数 // 根据n个元素的数组arr建立一个链表, 并返回链表的头 ListNode* createLinkedList(int arr[], int n){ if(n == 0) return NULL; ListNode* head = new ListNode(arr[0]); ListNode* curNode = head; for(int i = 1 ; i < n ; i ++){ curNode->next = new ListNode(arr[i]); curNode = curNode->next; } return head; } // 打印以head为头结点的链表信息内容 void printLinkedList(ListNode* head){ ListNode* curNode = head; while(curNode != NULL){ cout << curNode->val << " -> "; curNode = curNode->next; } cout << "NULL" << endl; return; } // 释放以head为头结点的链表空间 void deleteLinkedList(ListNode* head){ ListNode* curNode = head; while(curNode != NULL){ ListNode* delNode = curNode; curNode = curNode->next; delete delNode; } return; } // 206. Reverse Linked List // https://leetcode.com/problems/reverse-linked-list/description/ // 时间复杂度: O(n) // 空间复杂度: O(1) class Solution { public: 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; } }; int main(){ int arr[] = {1, 2, 3, 4, 5}; int n = sizeof(arr)/sizeof(int); ListNode* head = createLinkedList(arr, n); printLinkedList(head); ListNode* head2 = Solution().reverseList(head); printLinkedList(head2); deleteLinkedList(head2); return 0; }
运行结果以下:
进行了反转,没有问题;
LeetCode上第203题目:Remove Linked List Elements,题目以下:
从具备值val的整数链表中删除全部元素。 例子: 输入:1->2->6->3->4->5->6,val = 6 输出:1 - > 2 - > 3 - > 4 - > 5
先来分析一下题目,用图来解释以下:
假如删除值为4的节点,先把4的next指针保存,在3号位置指向5,这彻底没有问题;但问题会发生在第一个节点位置,它没有前一个节点,那怎么办呢?在前面建立链表时也说过:没有头结点,因此使用虚拟头结点!
代码以下:
// 203. Remove Linked List Elements // https://leetcode.com/problems/remove-linked-list-elements/description/ // 使用虚拟头结点 // 时间复杂度: O(n) // 空间复杂度: O(1) class Solution { public: ListNode* removeElements(ListNode* head, int val) { // 建立虚拟头结点 ListNode* dummyHead = new ListNode(0); dummyHead->next = head; ListNode* cur = dummyHead; while(cur->next != NULL){ if(cur->next->val == val){ ListNode* delNode = cur->next; cur->next = delNode->next; delete delNode; } else cur = cur->next; } ListNode* retNode = dummyHead->next; delete dummyHead; return retNode; } };
测试程序也是上面的链表建立和遍历,程序以下:
#include <iostream> using namespace std; ///Definition for singly-linked list. struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; /// LinkedList Test Helper Functions ListNode* createLinkedList(int arr[], int n){ if(n == 0) return NULL; ListNode* head = new ListNode(arr[0]); ListNode* curNode = head; for(int i = 1 ; i < n ; i ++){ curNode->next = new ListNode(arr[i]); curNode = curNode->next; } return head; } void printLinkedList(ListNode* head){ if(head == NULL){ cout << "NULL" << endl; return; } ListNode* curNode = head; while(curNode != NULL){ cout << curNode->val; if(curNode->next != NULL) cout << " -> "; curNode = curNode->next; } cout << endl; return; } void deleteLinkedList(ListNode* head){ ListNode* curNode = head; while(curNode != NULL){ ListNode* delNode = curNode; curNode = curNode->next; delete delNode; } return; } // 203. Remove Linked List Elements // https://leetcode.com/problems/remove-linked-list-elements/description/ // 使用虚拟头结点 // 时间复杂度: O(n) // 空间复杂度: O(1) class Solution { public: ListNode* removeElements(ListNode* head, int val) { // 建立虚拟头结点 ListNode* dummyHead = new ListNode(0); dummyHead->next = head; ListNode* cur = dummyHead; while(cur->next != NULL){ if(cur->next->val == val){ ListNode* delNode = cur->next; cur->next = delNode->next; delete delNode; } else cur = cur->next; } ListNode* retNode = dummyHead->next; delete dummyHead; return retNode; } }; int main() { int arr[] = {1, 2, 6, 3, 4, 5, 6}; int n = sizeof(arr) / sizeof(int); ListNode* head = createLinkedList(arr, n); printLinkedList(head); Solution().removeElements(head, 6); printLinkedList(head); deleteLinkedList(head); return 0; }
运行结果以下:
但愿经过这篇博客,你们能对基本的链表算法题能轻松应对;欢迎点赞,不懂的欢迎随时评论!多多支持,谢谢!