leetcode 链表

来源 leetcode.cn

1. 两数之和

题目链接

/*模拟加法*/
ListNode *addTwoNums(ListNode *l1, ListNode *l2){
	ListNode *head = nullptr, *tail = nullptr;
	while(l1 || l2){
		int n1 = l1 ? l1->val : 0;
		int n2 = l2 ? l2->val : 0;
		int carry = 0; 
		int sum = n1 + n2 + carry;
		if(!head){
			head = tail = new ListNode(sum % 10);
		}
		else{
			tail->next = new ListNode(sum % 10);
			tail = tail->next;
		}
		carry = sum / 10;
		if(l1) l1 = l1->next;
		if(l2) l2 = l2->next;
	} 
	if(carry) 
		tail->next = new ListNode(1);
	return head;
}

455. 两数相加II

题目链接

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 carry = 0;
	ListNode *ans = nullptr;
	while (!s1.empty() || !s2.empty() || carry) {
		int a = s1.empty() ? 0 : s1.top();
		int b = s2.empty() ? 0 : s2.top();
		if (!s1.empty()) s1.pop();
		if (!s2.empty()) s2.pop();
		int cur = a + b + carry;
		carry = cur / 10;
		cur %= 10;
		auto temp = new ListNode(cur);
		temp->next = ans;
		ans = temp;
	}
	return ans;
}
//Time O(max(m, n)) Space O(m+n)

1290. 二进制链表转整数

题目链接

int getDecimalValue(ListNode *head) {
	ListNode *cur = head;
	int ans = 0;
	while (cur) {
		ans = ans * 2 + cur->val;
		cur = cur->next;
	}
	return ans;
}	

19. 删除链表倒数第n个结点

题目链接
对链表操作时常用技巧是添加一个哑结点(dummy node),该节点的 next 指针指向链表头节点。这样操作不需要对头节点进行特殊判断。例如:删除链表某结点需要知道其前驱结点并修改前驱结点的后继指针,而对于删除头结点(没有前驱结点)需要特殊判断。

/*计算链表长度*/
ListNode *removeNthFromEnd(ListNode *head, int n){
	ListNode *dummy = new ListNode(0, head);
	int length = 0;
	while(head){
		++length;
		head = head->next;
	}
	ListNode *curr = dummy;
	for(int i = 0; i < length-n+1; i++)
		curr = curr->next;
	curr->next = curr->next->next;
	ListNode *res = dummy->next;
	delete dummy;
	return ans;
}
//Time: O(n) Space: O(1)
/*栈*/
ListNode *removeNthFromEnd(ListNode *head, int n){
	ListNode *dummy = new ListNode(0, head);
	stack<ListNode*> stk;
	ListNode *curr = dummy;
	while(curr){
		stk.push(curr);
		curr = curr->next;
	}
	for(int i = 0; i < n; i++)
		stk.pop();
	ListNode *prev = stk.top();   //precursor node
	prev->next = prev->next->next;
	ListNode *res = dummy->next;
	delete dummy;
	return res;
}
//Time: O(n) Space: O(n)
/*双指针*/
ListNode *removeNthFromEnd(ListNode *head, int n){
	ListNode *dummy = new ListNode(0, head);
	ListNode *fast = head, slow = dummy;
	for(int i = 0; i < n;; i++){
		fast = fast->next;
	while(fast){
		fast = fast->next;
		slow = slow->next;
	}
	slow->next = slow->next->next;
	ListNode *res = dummy->next;
	delete dummy;
	return res;
}
//Time: O(n) Space: O(n)

1721. 交换链表中的节点

题目链接

ListNode* swapNodes(ListNode *head, int k) {
	ListNode *fast = head, *slow = head;
	while (--k) fast = fast->next;
	ListNode *temp = fast;
	while (fast->next) 
		fast = fast->next, slow = slow->next;
	swap(temp->val, slow->val);
	return head;
}

2095. 删除链表的中间结点

题目链接

/*双指针*/
ListNode *deleteMiddle(ListNode *head) {
	if (!head->next) return nullptr;
	ListNode *fast = head, *slow = head;
	ListNode *pre = nullptr;
	while (fast && fast->next) {
		pre = slow;
		slow = slow->next;
		fast = fast->next->next;
	}
	pre->next = pre->next->next;
	return head;
}

21. 合并两个有序链表

题目链接

/*递归*/
ListNode* mergeTwoLists(ListNode *l1, ListNode *l2){
	if(l1 == nullptr)
		return l2;
	else if(l2 == nullptr)
		return l1;
	else if(l1->val < l2->val){
		l1->next = mergeTwoLists(l1->next, l2);
		return l1;          //error:non-void function does not return a value in all control paths
	}
	else{
		l2->next = mergeTwoLists(l1, l2->next);
		return l2;
	}
}
//Time: O(n+m)	Space: O(n+m) for recursive stack
/*迭代*/
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2){
	ListNode *dummy = new ListNode(-1);
	ListNode *curr = dummy;
	while(l1 && l2){
		if(l1->val < l2->val){
			curr->next = l1;
			l1 = l1->next;
		}
		else{
			curr->next = l2;
			l2 = l2->next;
		}
		curr = curr->next;
	}
	curr->next = l1 ? l1 : l2;
	return dummy->next;
}			

23. 合并k个升序链表

题目链接

/*逐个顺序合并*/
ListNode *mergeKList(vector<ListNode*>& List){
	ListNode *res = nullptr;
	for(size_t i = 0; i < list.size(); i++)
		res = mergeTwoLists(res, List[i]);
	return res;
}
  • 时间复杂度:假设每个链表最长长度是 n n n 。第 i 次合并后长度 i × n i \times n i×n。第 i 次合并的时间代价是 O ( i × n ) O(i \times n) O(i×n)。总时间代价 O ( ∑ i = 1 n ( i × n ) = O ( k 2 n ) O(\sum_{i=1}^n (i \times n) =O(k^2n) O(i=1n(i×n)=O(k2n)。空间复杂度: O ( 1 ) O(1) O(1)
/*分治(两两)合并*/
ListNode *merge(vector<ListNode*> &lists, int l, int r){
	if(l == r) return list[l];
	if(l > r) return nullptr;
	int mid = (l + r) >> 1;				//二分
	return mergeTwoList(merge(lists, l, mid), merge(lists, mid + 1, r));
}
ListNode *mergeKLists(vector<ListNode*> &lists){
	return merge(lists, 0, lists.size()-1);
}
  • 时间复杂度:考虑递归向上回升的过程——第一轮合并 k 2 \frac{k}{2} 2k 组链表,每组时间代价 O ( 2 n ) O(2n) O(2n) , 第二轮合并 k 4 \frac{k}{4} 4k 组链表,每组时间代价 O ( 4 n ) O(4n) O(4n)。总时间代价 O ( ∑ i = 1 ∞ k 2 i × 2 i n ) = O ( k n × log ⁡ k ) O(\sum_{i=1}^\infty \frac{k}{2^i} \times 2^in)=O(kn\times \log k) O(i=12ik×2in)=O(kn×logk) 。空间复杂度:递归需要 O ( log ⁡ k ) O(\log k) O(logk) 栈空间。
/*优先队列*/
struct comp{
	bool operator(){ListNode *a, ListNode *b){
		return a->val > b->val;
	}
};

priority_queue<ListNode*, vector<ListNode*>, comp> q;

ListNode *mergeKLists(vector<ListNode*> &lists){
	for(auto x : lists)
		if(x) q.push(node);
	ListNode *dummy = new ListNode();
	ListNode *curr = dummy;
	while(!q.empty()){
		ListNode* node = q.top();
		q.pop();
		curr->next = node;
		curr = curr->next;
		if(node->next) q.push(node->next);
	}
	return dummy->next;
}
  • 时间复杂度:优先队列中元素不超过 k 个,插入和删除的时间代价为 O ( log ⁡ k ) O(\log k) O(logk),最多 k n kn kn 个点,每个店都插入删除各一次。总时间复杂度 O ( k n × log ⁡ k ) O(kn \times \log k) O(kn×logk).。空间复杂度 O ( k ) O(k) O(k)

1669. 合并两个链表

题目链接

ListNode *mergeInBetween(ListNode *list1, ListNode *list2, int a, int b) {
	ListNode *la, *b, *cur = list1;
	int i = 0;
	while (cur) {
		if (i == a - 1) la = cur;
		if (i == b + 1) lb = cur;
		i++;
		cur = cur->next;
	}
	la->next =list2;
	while (list2->next)
		list2 = list2->next;
	list2->next = lb;
	return list1;
} 

24. 两两交换链表中节点

题目链接

/*递归*/
ListNode *swapPairs(ListNode *head){
	if(head == nullptr || head->next == nullptr)
		return head;								//递归出口:链表只剩1个或0个结点,无变化直接返回
	ListNode *newHead = head->next;					//指针记录下需要交换的两结点:当前结点head与当前结点后继结点newHead
	head->next = swapPairs(newHead->next);			//修改当前结点后继指针:两节点一层,层层进入递归。
	newHead->next = head;							//处理最后一层指针变化
	return newHead;									//本层产生的newHead作为上层的head的后继结点即head->next返回给上层
}
//Time: O(n) Space: O(n)
  • 递归终止条件是链表无节点或只有一个结点。若链表至少两个结点情况原始头结点变为新链表第二个节点,原始第二个节点变成新链表新头结点,余下结点两两成组交换可以递归实现。更新结点指针关系完成结点交换。
/*迭代*/
ListNode *swapPairs(ListNode *head){
	ListNode *dummy = new ListNode(0, head);
	ListNode *cur = dummy;
	while(cur->next && cur->next->next){
		ListNode *temp1 = cur->next;
		ListNode *temp2 = cur->next->next;
		cur->next = temp2;
		temp1->next = temp2->next;
		temp2->next = temp1;
		cur = temp1;    // or cur = cur->next->next;
	}
	return dummy->next;
}	
//Time: O(n) Space: O(1)

206. 反转链表

题目链接

/*递归*/
ListNode *reverseList(ListNode *head){
	if(!head || !head->next)	//链表只有一个结点或者至少两个结点情况的递归出口	
		return head;			//想象递归到链表尾倒数第一个结点,弹出作为上层的newHead结点进行返回
	ListNode *newHead = reverseList(head->next); 	//从头结点开始一路层层进入递归,每层递归返回时都是尾部的链表结点已经实现翻转,层层向前回溯
	head->next->next = head;
	head->next = nullptr;		//翻转调节指针
	return newHead;				//返回本层产生的newHead作为上层的newHead(事实上一直是最后一个结点不变,也即新链表的头结点)
}
//Time: O(n) Space: O(n)	
  • 画图。
/*迭代*/
ListNode *ReverseList(ListNode *head){
	ListNode *prev = nullptr, *cur = head;
	while(cur){
		ListNode *temp = cur->next;
		cur->next = prev;
		prev = cur;
		cur = temp;
	}
	return prev;			//此时cur指向最后一节点的后继结点即nullptr
}
//Time: O(n) Space: O(1)

92. 反转链表II

/*类似206*/
void reverseList(ListNode *head){		//注意这里是void
	ListNode *pre = nullptr;
	ListNode *cur = head;
	while(cur){
		ListNode temp = cur->next;
		cur->next = pre;
		pre = cur;
		cur = temp;
	}
}
ListNode *reverseBetween(ListNode *head, int left, int right){
	//头结点可能发生变化,故使用哑结点
	ListNode *dummy = new ListNode(0,head);
	LisNode *pre = dummy;

	//1.找到left结点
	for(int i = 0; i < left - 1; i++)
		pre = pre->next;
	ListNode *leftNode = pre->next;
	
	//2.找到right结点
	ListNode *rightNode = pre;
	for(int i = 0; i < right - left + 1; i++)
		rightNode = rightNode->next;
	
	//3.切出子链表
	ListNode *curr = rightNode->next;
	pre->next = nullptr, rightNode->next = nullptr;

	//4.反转
	reverseList(leftNode);

	//5.复原
	pre->next = rightNode;
	leftNode->next = curr;
	return dummy->next;
}
//Time O(n) Space O(1)
//但是如果left right区域趋近整个链表长度,需要遍历两次(找点+反转)
/*头插法实现反转*/
ListNode *reverseBetween(ListNode *head, int left, int right){
	ListNode *dummy = new ListNode(0, head);
	ListNode *pre = dummy;
	for(int i = 1; i < left; i++)
		pre = pre->next;
	ListNode cur = pre->next;
	for(int i = 0; i < right - left; i++){
		ListNode *temp = cur->next;
		cur->next = temp->next;
		temp->next = cur;
		pre->next = temp;		//注意此处没有cur = cur->next; 因为头插法cur指针所指结点会慢慢沉降到最后一位
	}
	return dummy->next;
}
//Time O(n) Space O(1)
//只遍历了一遍,头插法反转链表		

2130. 链表最大孪生和

题目链接

/*双指针 + 反转链表*/
int pairSum(ListNode *head) {
	ListNode *slow = head, *fast = head->next;
	while (fast->next) {
		slow = slow->next;
		fast = fast->next->next;
	}
	ListNode *last = slow->next;
	while (last->next) {
		ListNode *temp = last->next;
		last->next = temp->next;
		temp->next = slow->next;			//进入循环后last 就不等同于 slow->next 了
		slow->next = temp;
	}
	int ans = 0;
	ListNode *x = head, *y = slow->next;
	while (y) {
		ans = max(ans, x->val + y->val);
		x = x->next;
		y = y->next;
	}
	return ans;
}	

2074. 反转偶数长度数组的结点

题目链接

ListNode *reverseEvenLengthGroup(ListNode *head) {
	ListNode *dummy = new ListNode(0, head);
	ListNode *pre = dummy, *cur = head;
	int grp = 0;
	while (cur) {
		++grp;
		ListNode *it = cur;
		int length = 0;
		while (length < grp && it) {
			it = it->next;
			++length;
		}
		if (length % 2 == 0) {
			for (int i = 0; i < length - 1; i++) {
				ListNode *temp = cur->next;
				cur->next = cur->next->next;
				temp->next = pre->next;
				pre->next = temp;						//头插法反转链表
			}
			pre = cur;
			cur = cur->next;
		}
		else {
			for (int i = 0; i < length; i++){
				cur = cur->next;
				pre = pre->next;
			}
		}
	}
	return dummy->next;
}		
//Time O(n) Space O(1) 每段最多被遍历两次

25. k个一组翻转链表

题目链接

ListNode* reverseList(ListNode* head, ListNode* tail){			//tail为下一子区间的头结点
	ListNode *prev = nullptr, *cur = head;
	while(cur != tail){
		ListNode *temp = cur->next;
		cur->next = prev;
		cur = temp;
	}
	return prev;
}

ListNode* reverseKGroup(ListNode* head, int k){
	ListNode *dummy = new ListNode(0, head);
	ListNode *cur = dummy;
	ListNode *fast = head, *slow = head;
	while(fast != nullptr){
		int cnt = 0;
		for( ; cnt < k && fast != nullptr; cnt++)
			fast = fast->next;
		if(cnt == k){
			ListNode *subHead = reverseList(slow, fast);
			cur->next = subHead;
			cur = slow;
			slow = fast;
		}
		else
			cur->next = slow;
	}
	return dummy->next;
}	

61. 旋转链表

题目链接

/*成环再断链*/
ListNode* rotateRight(ListNode *head, int k){
	if(k == 0 || head == nullptr || head->next == nullptr)
		return head;
	ListNode* iter = head;
	int n = 1;
	while(iter->next){
		iter = iter->next;
		n++;
	}
	int move = n - k % n;
	if(move == n)
		return head;
		
	iter->next = head;
	while(move--)
		iter = iter->next;
	ListNode *res = iter->next;
	iter->next = nullptr;
	return res;
}
//Time O(n) Space O(n)

83. 删除排序链表中重复元素

题目链接

ListNode* deleteDuplicates(ListNode *head){
	if(!head) return head;
	ListNode *cur = head;
	while(cur->next){
		if(cur->val == cur->next->val)
			cur->next = cur->next->next;
		else
			cur = cur->next;
	}
	return head;
}

82. 删除排序链表中重复元素II

题目链接

ListNode* deleteDuplicates(ListNode *head){
	if(!head || !head->next) return head;
	ListNode *dummy = new ListNode(0, head);
	ListNode *cur = dummy;
	while(cur->next && cur->next->next){
		if(cur->next->val == cur->next->next->val){		//在当前cur指针,对比cur.next和cur.next.next值是否相等
			int i = cur->next->val;
			while(cur->next && cur->next->next->val == i)
				cur->next = cur->next->next;
		}
		else
			cur = cur->next;
	}
	return dummy->next;
}	
  • 不同于上题的的地方在于上题保留一个重复元素,而本题要删除所有重复元素。故会产生删除头结点情况,所以引入哑结点。此外,导致进入第一个while循环的判断条件也不同,一个在当前指针 cur 处,用 cur 值对比 cur.next 的值;一个是在当前指针 cur 处,用 _cur.next_的值对比 cur.next.next 的值。

86. 分隔链表

题目链接

/*维护两个链表*/
ListNode *partition(ListNode *head, int x){
	ListNode *small = new ListNode(0);
	ListNode *large = new ListNode(0);
	ListNode *s = small, *l = large;
	while(head){
		if(head->val < x){
			small->next = head;
			small = small->next;
		}
		else{
			large->next = head;
			large = large->next;
		}
		head = head->next;
	}
	large->next = nullptr;		//链表尾结点指向null
	small->next = l->next;
	return s->next;
}

725. 分隔链表

题目链接

/*If there are N nodes in the list, and k parts, 
then every part has N/k elements, except the first N%k parts have an extra one.*/
vector<ListNode*> splitListToParts(ListNode *head, int k) {
	int cnt = 0;
	ListNode *trav = head;
	while (trav) {
		cnt++;
		trav = trav->next;
	}
	int quotient = cnt / k, remainder = cnt % k;

	vector<ListNode*> parts(k, nullptr);
	ListNode *curr = head;
	for (int i = 0; i < k && cur; i++) {
		parts[i] = curr;
		int partSize = quotient + (i < remainder ? 1 : 0);
		for (int j = 1; j < partSize; j++) 
			curr = curr->next;
		ListNode *next = curr->next;
		curr->next = nullptr;
		curr = next;
	}
	return parts;
}

328. 奇偶链表

/*维护两个链表*/
ListNode *oddEvenList(ListNode *head) {
	if (!head) return head;
	ListNode *evenHead = head->next;
	ListNode *odd = head, *even = head->next;
	while (even && even->next) {
		odd->next = even->next;
		odd = odd->next;
		even->next = odd->next;
		even = even->next;			//两个节点一组
	}
	odd->next = evenHead;
	return head;
}

138. 复制带随机指针的链表

题目链接
由于随机指针的存在,当拷贝某结点时,该节点的随机指针指向的结点可能还没有创建。

/*回溯 + 哈希表*/
class Node{
public:
	int val;
	Node *next;
	Node *random;
	Node(int _val){
		val = _val;
		next = NULL;
		random = NULL;
	}
};

class Sol{
public:
	unordered_map<Node*, Node*> cacheNode;

	Node* copyRandomList(Node *head){
		if(!head) return nullptr;
		if(!cacheNode.count(head)){
			Node *headNew = new Node(head->val);
			cacheNode[head] = headNew;
			headNew->next = copyRandomList(head->next);
			headNew->random = copyRandomList(head->random);		//递归回溯实现后继与随机指针赋值操作分离
		}
		return cacheNode[head];
	}
}	
//Time O(n); Space O(n) for hash
  • 利用回溯的方式,让每个结点的拷贝操作相互独立。对于当前结点首先进行拷贝,然后进行 当前结点的后继结点当前结点的随机指针指向结点 拷贝,拷贝完成后将出案件的新节点返回,即可完成当前结点的两指针赋值。
/*迭代 + 节点拆分*/
Node* copyrandomList(Node *head){
	if(!head) return nullptr;
	
	for(Node *i = head; i; i = i->next->next){
		Node* newNode = new Node(i->val);
		newNode->next = i->next;
		i->next = newNode;
	}

	for(Node *i = head; i; i = i->next->next){
		Node* newNode = i->next;
		newNode->random = i->random ? i->random->next : nullptr;
	}
	
	Node* headNew = head->next;
	for(Node* i = head; i; i = i->next){
		Node* newNode = i->next;
		i->next = newNode->next;
		newNode->next = newNode->next ? newNode->next->next : nullptr;
	}
	return headNew;
}	
  • 将复制节点链于源节点之后,形如 A → A ′ → B → B ′ A\rightarrow A'\rightarrow B\rightarrow B' AABB ,拷贝随机结点后断链。

141. 环形链表

题目链接

/*哈希表*/
bool hasCycle(ListNode *head){
	unordered_set<ListNode*> seen;
	while(head){
		if(seen.count(head))
			return true;
		seen.insert(head);
		head = head->next;
	}
	return false;
}
//Time O(n) Space O(n)
/*双指针*/
bool hasCycle(ListNode *head){
	if(!head || !head->next) return false;
	ListNode *slow = head;
	ListNode *fast = head->next;
	while(slow != fast){
		if(!fast || !fast->next)
			return false;
		slow = slow->next;
		fast = fast->next->next;
	}
	return true;
}
//Time O(n) Space O(n) 

142. 环形链表II

题目链接

/*双指针*/
ListNode *detectCycle(ListNode *head){
	ListNode *fast = head, *slow = head;
	while(fast){
		if(fast->next){
			fast = fast->next->next;
			slow = slow->next;
			if(slow == fast){
				slow = head;
				while(fast != slow){
					slow = slow->next;
					fast = fast->next;
				}
				return slow;
			}
		}
		else 
			break;
	}
	return nullptr;
}	
/*哈希表*/
ListNode *detectCycle(ListNode *head){
	unordered_set<ListNode*> visited;
	while(head){
		if(visited.count(head))
			return head;
		visited.insert(head);
		head = head->next;
	}
	return nullptr;
}

876. 链表中间结点

题目链接

/*双指针*/
ListNode* middleNode(ListNode *head) {
	ListNode *slow = head, *fast = head;
	while (fast && fast->next) {
		fast = fast->next->next;
		slow = slow->next;
	}
	return slow;
}
//与下题重排链表中的中点函数不同之处在于while循环判断条件,
//本题(偶数个)返回第二个中间结点,下题返回第一个中间结点

143. 重排链表

题目链接

/*线性表*/
void reorederList(ListNode *head){
	if (!head) reutrn;
	vector <ListNode*> vec;
	ListNode *node = head;
	while(node){
		vec.emplace_back(node);
		node = node->next;
	}
	int i = 0, j = vec.size() - 1;
	while (i < j){
		vec[i]->next = vec[j];
		i++;
		if(i == j) break;
		vec[j]->next = vec[i];
		j--;
	}
	vec[i]->next = nullptr;
}
/*寻找链表中点 + 链表逆序 + 链表合并*/
ListNode *midNode(ListNode *head){
	ListNode *slow = head, *fast = head;
	while(fast->next && fast->next->next){
		slow = slow->next;
		fsat = fast->next->next;
	}
	return slow;
}

ListNode *reverseList(ListNode *head){
	ListNode *pre = nullptr, *cur = head;
	while(cur){
		ListNode *temp = cur->next;
		cur->next = pre;
		pre = cur;
		cur = temp;
	}
	return pre;
}

void mergeList(ListNode *a, ListNode *b){
	while (a && b){
		ListNode *temp1 = a->next, *temp2 = b->next;
		a->next = b;
		a = temp1;
		b->next = a;
		b = temp2;
	}
}
		 
void reorderList(ListNode *head){
	if (!head) return ; 
	ListNode *mid = midNode(head);
	ListNode *list1 = head, *list2 = mid->next;
	mid->next = nullptr;
	list2 = reverseList(list2);
	mergeList(list1, list2);
}	

147. 链表的插入排序

题目链接

/*插入排序*/
ListNode *insertionSortList(ListNode *head){
	if(!head || !head->next) return head;
	ListNode *dummy = new ListNode(0, head);			//哑结点便于在head结点之前插入新节点
	ListNode *lastSorted = head;						//维护已排序部分地最后一个结点
	ListNode *cur = head->next;							//跟踪当前处理的结点
	while(cur){
		if(lastSorted->val <= cur->val)
			lastSorted = lastSorted->next;
		else{
			ListNode *prev = dummy;  					//需要插入在结点之后的位置
			while(prev->next->val <= cur->val)
				prev = prev->next;
			lastSorted->next = cur->next;				//
			cur->next = prev->next;						//摘除cur结点
			pre->next = cur;							//安装cur结点
		}
		cur = lastSorted->next;							//原cur结点已经插入至前列
	}
	return dummy->next;
}	
//Time O(n^2) Space O(1)

148. 链表归并排序

题目链接

/*自顶向下的归并排序(递归)*/
ListNode *sortList(ListNode* head){
	return sortList(head, nullptr);
}
ListNode *sortList(ListNode *head, ListNode *tail){
	if (!head) return head;
	if (head->next == tail){
		head->next = nullptr;
		return head;
	}
	ListNode *slow = head, *fast = head;
	while (fast != tail) {
		slow = slow->next;
		fast = fast->next;
		if(fast != tail)
			fast = fast->next;
	}
	ListNoode *mid = slow;
	return merge(sortList(head, mid), sortList(mid, tail);
}

ListNode *merge(ListNode *head1, ListNode *head2){
	ListNode *dummy = new ListNode(0);
	ListNode *cur = dummy, *temp1 = head1, *temp2 = head2;
	while (temp1 && temp2) {
		if (temp1->val <= temp2->val) {
			cur->next = temp1;
			temp1 = temp1->next;
		} 
		else {
			cur->next = temp2;
			temp2 = temp2->next;
		}
		cur = cur->next;
	}
	cur->next = temp1 ? temp1 : temp2;
	return dummy->next;
}
//Time O(nlogn) Space O(logn)
/*改进的递归*/
ListNode *sortList(ListNode *head) {
	if (!head || !head->next) return head;
	ListNode *slow = head, *fast = head;
	while (fast->next && fast->next->next) {
		fast = fast->next->next;
		slow = slow->next;
	}
	ListNode *mid = slow->next;
	slow->next = nullptr;
	return merge(sortList(head), sortList(mid));
}
ListNode *merge(ListNode *head1, ListNode *head2){
	/* same code as above */
}
/*自底向上的递归排序*/
ListNode* sortList(ListNode *head) {
	if (head == nullptr) return head;
	int length = 0;
	ListNode *node = head;
	while (node){
		node = node->next;
		length++;
	}
	
	//将链表拆成若干长度为sub的子链表,两个一组合并成若干个2*sub长度的有序子链表
	ListNode *dummy = new ListNode(0, head);
	for (int subLength = 1; subLength < length; subLength <<= 1) {
		//cur用于记录拆分链表的位置
		ListNode *prev = dummy, *cur = dummy->next;
		while (cur) {
			//拆出一个sub长度的链表
			ListNode *head1 = cur;
			for(int i = 1; i < subLength && cur->next; i++)
				cur = cur->next;
			
			//拆出第二个sub长度的链表
			ListNode *head2 = cur->next;
			cur->next = nullptr;			//断链
			cur = head2;
			for (int i = 1; i < subLength && cur && cur->next; i++) 
				cur = cur->next;
			
			//next记录拆分完两个链表结束位置	
			ListNode *next = nullptr;		
			if (cur) {
				next = cur->next;
				cur->next = nullptr;		//断链
			}

			//合并前两个sub长度的子链
			ListNode *merged = merge(head1, head2);
			prev->next = merged;			//prev指向排好序的链表头
			while (prev->next)
				prev = prev->next;			//prev移动至sub*2的位置
			cur = next;						//cur到达上次拆分结束位置
		}
		//while一轮结束,sub长度一轮拆并结束,进入for循环进行下一轮sub*2长度的拆并
	}
	return dummy->next;
}

ListNode *merge(ListNode *head1, ListNode *head2){
	/* same code as above */
}
//Time O(nlogn) Space O(1)			

160. 相交链表

题目链接

/*哈希表*/
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
	unordered_set<ListNode *> visited;
	ListNode *temp = headA;
	while (temp) {
		visted.insert(temp);
		temp = temp->next;
	}
	temp = headB;
	while (temp) {
		if (visited.count(temp))
			return temp;
		temp = temp->next;
	}
	return nullptr;
}
//Time O(m+n) Space O(m)
/*双指针*/
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
	if (!headA || !headB) return nullptr;
	ListNode *a = headA, *b = headB;
	while (a != b) { 
		a = !a ? headB : a->next;
		b = !b ? headA : b->next;
	}
	return a;
}

203. 移除链表元素

题目链接

/*迭代*/
ListNode *removeElement(ListNode *head, int val) {
	ListNode *dummy = new ListNode(0, head);
	ListNode *cur = dummy;
	while (cur->next) {
		if (cur->val == val)
			cur->next = cur->next->next;
		else
			cur = cur->next;
	}
	return dummy->next;
}	
//Time O(n) Space O(1)
/*递归*/
ListNode *removeElement(ListNode *head, int val){
	if (haed == nullptr) 
		return head;
	head->next = removeElement(head->next, val);
	return head->val == val ? head->next : head;
}
//Time O(n) Space O(1)

234. 回文链表

题目链接

/*优雅的递归*/
ListNode *frontPointer; 			//全局变量
bool recursivelyCheck(ListNode* currentNode) {
	if (currentNode) {
		//回溯时下层返回的如果是false,本层if条件成立返回上层false;如果下层返回true,不进入if条件判断直接跳过本语句
		if (!recursivelyCheck(currentNode->next))	
			return false;
		if (currentNode->val != frontPointer->val)
			return false;
		frontPointer = frontPointer->next;
	}
	return true;
}
bool isParlindrome(ListNode *head) {
	frontPointer = head;
	return recursivelyCheck(head);
}
//Time O(n) Space O(n)
/*快慢指针,修改链表*/
bool isPalindrome(ListNode *head) {
	if (!head) return true;
	ListNode *firstHalfEnd = endOfFirstHalf(head);
	ListNode *secondHalfStart = reverseList(firstHalfEnd->next);
	ListNode *p1 = head, *p2 = secondHalfStart;
	bool res = true;
	while (res && p2) {
		if (p1->val != p2->val) 
			res =false;
		p1 = p1->next;
		p2 = p2->next;
	}
	firstHalfEnd->next = reverseList(secondHalfStart);
	return res;
}

ListNode *reverseList(ListNode *head) {
	ListNode *prev = nullptr;
	ListNode *curr = head;
	while (curr) {
		ListNode *temp = curr->next;
		curr->next = prev; 
		prev = curr;
		curr = temp;
	}
	return prev;
}

ListNOde *endOfFirstHalf(ListNode *head) {
	ListNode *fast = head, *slow = head;
	while(fast->next && fast->next->next) {
		fast = fast->next->next;
		slow = slow->next;
	}
	return slow;
}
//Time O(n) Space O(1)

237. 删除链表中的结点

题目链接

void deleteNode(ListNode *node){
	node->val = node->next->val;
	ListNode *temp = node->next;
	node->next = node->next->next;
	delete temp;
}

430.扁平化多级链表

题目链接

/*迭代*/
/*以整段(层)为单位进行扁平化*/
Node *flatten(Node *head) {
	Node *dummy = new Node(0);
	dummy->next = head; 			//免去特判head为空情况
	for ( ; head; head = head->next) {
		Node *next = head->next, *child = head->child;
		head->next = child;
		head->child = nullptr;
		child->prev = head;
		Node *temp = child;
		while (temp->next)
			temp = temp->next;
		if (next) next.prev = temp;
		temp->next = next;
	}
	return dummy->next;
}
//Time O(n) Space O(1)
/*递归 dfs*/
Node* faltten(Node *head) {
	dfs(head);
	return head;
}
Node* dfs(Node* head) {
	Node *last = nullptr, *cur = head;
	while (cur) {
		Node *next = cur->next;
		if (cur->child) {
			Node *child_last = dfs(cur->child);	
			cur->next = cur->child;
			cur->child->prev = cur;
			cur->child = nullptr;
			if (next) {
				next->prev = child_last;
				child_last->next = next;
			}
			last = child_last;
		}
		else
			cur = next;
	}
	return last;
}	
//Time O(n), Space O(d) for stack, d for list deep, worse case for O(n)

817. 链表组件

题目链接

/*哈希表 + 线性扫描*/
int numComponents(ListNode *head, vector<int> &nums) {
	unordered_set <int> set(nums.begin(), nums.end());
	int cnt = 0;
	ListNode *trav = head;
	while (trav) {
		if (set.count(trav->val) && (!trav->next || !set.count(trav->next->val)))
			cnt++;
		trav = trav->next;
	}
	return cnt;
}	

1019. 链表中的下一个更大结点

题目链接

  • 单调栈 : 在队列或数组中我们需要比较前后元素的大小关系来解决问题时我们通常使用单调栈。例题:在一个队列中针对每一个元素从他的右边寻找第一个比它大的元素。
/*单调栈:栈解决链表不能向前回溯*/
vector<int> nextLargerNode(ListNode *head) {
	int count = 0;
	vector<int> res;
	stack<pair<int, int>> tmp;		//pair.first->val, pair.second->index
	while (head) {
		res.push_back(0);
		while (!tmp.empty() && tmp.top().first < head->val){
			res[tmp.top().second] = head->val;
			tmp.pop();		
		}
		tmp.push(make_pair(head->val, count++));
		head = head->next;
	}
	return res;
}
//Time O(n) Space O(n)

2289. 使数组按非递减顺序排列

题目链接

/*单调栈*/
//对于每个 num[i] 如果它被消除,要么是被左侧最近的更大的元素消除,要么是左侧最近的更大元素已经被消除后有左侧次近的元素消除
//单调栈求左侧第一个更大元素
//设 nums[i] 被 nums[j] 消除。那么位于 j 和 i 之间的元素一定首先被消除。设 f[i] 为 nums[i] 被消除所需的轮数,则 f[i] = max(f[j+1]...f[i-1]) + 1。
int totalSteps(vector<int> &nums) {
	int res = 0;
	int  f[nums.size()];
	stack<int> st;
	for (int i = 0; i < nums.size(); i++) {
		int cur = 0;
		while (st.size() && nums[st.top()] <= nums[i]) {
			cur = max(cur, f[st.top()];
			st.pop();
		}
		if (st.size()) {
			res = max(res, cur + 1);
			f[i] = cur + 1;
		}
		st.push(i);
	}
	return res;
}
//Time O(n) Space O(n)
/*单调栈*/
//单调递减栈存储元素以及其被删除的时刻,当遇到一个不小于栈顶元素 x 时,就不断弹出栈顶元素,并取弹出元素被删除时刻的最大值
int totalSteps(vector<int> &nums) {
	int ans = 0;
	stack<pair<int, int>> st;
	for(int it : nums) {
		int maxT = 0;
		while (!st.empty() && st.top().first <= it) {
			maxT = max(maxT, st.top().second);
			st.pop():
		}
		maxT = st.empty() ? 0 : maxT + 1;
		ans = max(ans, maxT);
		st.emplace(x, maxT);
	}
	return ans;
}
//Time O(n) Space O(n)		

1171. 从链表中删去总和值为零的连续结点

题目链接

/*前缀和 + 哈希表*/
//对于前缀和相同的项,那他们中间的部分可以消掉
ListNode *removeZeroSumSublists(ListNode *head) {
	unordered_map<int ,ListNode*> prefixSum;
	ListNode* dummy = new ListNode(0, head), *trav = dummy;
	prefixSum[0] = trav;
	int sum = 0, temp = 0;
	while (trav = trav->next) {				//此判断条件先进行下指针寻找行动后再判断结点是否存在
		sum += trav->val;
		if (prefixSum.find(sum) != prefixSum.end()) {
			ListNode *next = prefixSum[sum]->next;
			prefixSum[sum]->next = trav->next;
			temp = sum;
			while (next != trav) {
				temp += next->val;
				prefixSum.erase(temp);			//删除map表中相关元素
				next = next->next;
			} 
		} else 
			prefixSum[sum] = trav;
	}
	return dummy->next;
}	

2058. 找出临界点之间最小和最大距离

题目链接

/*维护第一个和上一个临界点位置*/
vector<int> nodesBetweenCriticalPoints(ListNode *head) {
	int minDist = -1, maxDist = -1;
	int first = -1, last = -1, pos = 0;
	ListNode *cur = head;
	while (cur->next->next) {
		int x = cur->val;
		int y = cur->next->val;
		int z = cur->next->next->val;
		if (y > max(x, z) || y < min(x, z)) {
			if (last != -1) {
				minDist = (minDist == -1 ? pos - last : min(minDist, pos - last));
				maxDist = max(maxDist, pos - first);
			}
			if (first == -1)
				first = pos;
			last = pos;
		}
		cur = cur->next;
		++pos;
	}
	return {minDist, maxDist};
}	

2181. 合并零之间的节点

题目链接

ListNode *mergeNodes(ListNode *head){
	ListNode *dummy = new ListNode()
	ListNode *tail = dummy;
	int total = 0;
	for (ListNode *cur = head->next; cur; cur = cur->next) {
		if (cur->val == 0) {
			ListNode *node = new ListNode(total);
			tail->next = node;
			tail = tail->next;
			total = 0;
		}
		else
			total += cur->val;
	}
	return dummy->next;
}	

146. 设计LRU缓存

题目链接

/*哈希表 + 双向链表*/
struct DLinkedNode{
	int key, value;
	DLinkedNode *prev;
	DLinkedNode *next;
	DLinkedNode(): key(0), value(0), prev(nullptr), next(nullptr) {}
	DLinkedNode(int _key, int _value): key(_key), value(_value), prev(nullptr), next(nullptr){}
};

class LRUCache{
private:
	unordered_map <int, DLinkedNode*> cache;
	DLinkedNode *head;
	DLinkedNode *tail;
	int size;
	int capacity;

public:
	LRCache(int _capacity): capacity(_capacity), size(0){
		//使用伪头结点和伪尾结点(类似dummy)
		head = new DLinkedNode();
		tail = new DLinkedNode();
		head->next = tail;
		tail->prev = head;
	}
 	
 	int get(int key){
 		if(!cache.count(key))
 			return -1;
 		//如果key存在,通过哈希表定位,然后移动节点到头部
 		DLinkedNode *node = cache[key];
 		moveToHead(node);
 		return node->value;
 	}
 	
 	void put(int key, int value){
 		if(!cache.count(key)){
 			//若果key不存在就创建新节点
 			DLinkedNode *node = new DLinkedNode(key, value);
 			//添加入哈希表
 			cache[key] = node;
 			//添加至双向链表头部
 			addToHead(node);
 			++size;
 			if(size > capacity){
 				//超出容量,删除双向链表尾部节点
 				DLinkedNode *removed =removeTail();
 				//删除哈希表对应项
 				cache.erase(removed->key);
 				//防止内存泄露
 				delete removed;
 				--size;
 			}
 		}
 		else{
 			//如果key存在,通过哈希定位,修改value,并移动到头部
 			DLinkedNode *node = cache[key];
 			node->value = value;
 			moveToHead(node);
 		}
 	}
	
	void addToHead(DLinkedNode *node){
		//双向链表头插法
		node->prev = head;
		node->next = head->next;
		head->next->prev = node;
		head->next = node;
	}
	
	void removeNode(DLinkedNode *node){
		//双向链表移除点
		node->prev->next = node->next;
		node->next->prev = node->prev;
	}

	void moveToHead(DLinkedNode *node){
		removeNode(node);
		addToHead(node);
	}

	DLinkedNode* removeTail(){
		DLinkedNode* node = tail->prev;
		removeNode(node);
		return node;
	}
}; 		

432. 全O(1)的数据结构

题目链接

/*双向链表 + 哈希表*/
class AllOne {

	//双链链表结点存储一个字符串集合keys,和一个正整数count表示次数,链表顺序为依据count单调递增
	list<pair<unordered_set<string>, int>> lst;
	//哈希表nodes维护每个字符串所处链表结点
	unordered_map<string, list<pair<unordered_set<string>, int>>::iterator> nodes;
	
public:
	//初始化数据结构的对象
	AllOne() {}
	
	//插入字符串
	void inc(string key) {
		//key在链表中
		if(nodes.count(key)) {
			auto cur = nodes[key], nxt = next(cur);
			//插入一个count=cur.count+1的新节点到cur后
			if(nxt == lst.end() || nxt->second > cur->second + 1){
				unordered_set<string> s({key});
				nodes[key] = lst.emplace(nxt, s, cur->second + 1);
			} else {
				nxt->first.emplace(key);
				nodes[key] = nxt;
			}
			//将key从cur.keys中删除
			cur->first.erase(key);
			//如果cur.keys为空cur从链表删除
			if (cur->first.empty()) 
				lst.erase(cur);
		} 
		//key不在链表里
		else {
			if (lst.empty() || lst.begin()->second > 1) {
				unordered_set<string> s({key});		
				lst.emplace_front(s, 1); 		//插入一个count=1的新节点至链表头部
			} else {
				lst.begin()->first.emplace(key);
			nodes[key] = lst.begin();			//key插入头结点的keys中
		}
	}
	
	void dec(string key) {
		auto cur = nodes[key];
		if(cur->second == 1)
			nodes.erase(key);
		else {
			auto pre = prev(cur);
			if (cur == lst.begin() || pre->second < cur->second - 1) {
				unordered_set<string> s({key});
				nodes[key] = lst.emplace(cur, s, cur->second - 1);
			}
			else {
				pre->first.emplace(key);
				nodes[key] = pre;
			}
		}
		cur->first.erase(key);
		if (cur->first.empty())
			lst.erase(cur);
	}

	string getMaxKey() {
		return lst.empty() ? "": *lst.rbegin()->first.begin();
	}

	string getMinKey() {		
		return lst.empty() ? "" : *lst.begin()->first.begin();
	}
};		

AllOne* obj = new AllOne();
obj->inc(key);
obj->dec(key);
string param_3 = obj->getMaxKey();
string param_4 = obj->getMinKey();

//Time O(1) Space O(I) for hash time, I for times of calling inc()		

460. LFU缓存

题目链接

/*双哈希表*/
struct Node{
	int key, val, freq;
	Node(int _key, int _val, int _freq): key(_key), val(_val), freq(_freq) {}
};
class LFUCache {
	int minfreq, capacity;
	//以key为索引,每个索引存放对应缓存在freq_table中链表的内存位置
	unordered_map<int, list<Node>::iterator> key_table;
	//以freq为索引,每个索引存放一个双向链表。链表中存放所有使用频率为freq的缓存,缓存中存放三个信息:键、值、使用频率
	unordered_map<int, list<Node>> freq_table;
public:
	LFUCache(int _capacity) {
		minfreq = 0;				//当前缓存最小频率服务删除操作
		capacity = _capacity;
		key_table.clear();
		freq_table.clear();
	}
	
	//如果键key存在于缓存中,则获取键的值,否则返回-1
	int get(int key) {
		if (capacity == 0) return -1;
		auto it = key_table.find(key);
		if (it == key_table.end()) return -1;
		list<Node>::iterator node = it->second;
		int val = node->val, freq = node->freq;
		freq_table[freq].erase(node);
		if (freq_table[freq].size() == 0) {		//如果当前链表清空,则需要在哈希表中删除且更新最小频率
			freq_table.erase(freq);
			if (minfreq == freq) 
				minfreq += 1;
		}
		freq_table[freq + 1].push_front(Node(key, val, freq + 1));		//插入到 freq+1 中
		key_table[key] = freq_table[freq + 1].begin();
		return val;
	}
		
	//若键key存在则变更其值;不存在则插入其键值对;缓存容量满则移除最不经常使用的
	void put(int key, int value) {
		if (capacity == 0) return ;
		auto it = key_table.find(key);
		//缓存满需要删除
		if (it == key_table.end()) {
			if (key_table.size() == capacity) {
				auto it2 = freq_table[minfreq].back();		//通过 minfreq 拿到 freq_table[minfreq] 链表的末尾结点
				key_table.erase(it2.key);
				freq_table[minfreq].pop_back();
				if (freq_table[minfreq].size() == 0)
					freq_table.erase(minfreq);
			}
			freq_table[1].push_front(Node(key, value, 1);
			key_table[key] = freq_table[1].begin();
			minfreq = 1;
		}
		
		else {
			list<Node>::iterator node = it->second;
			int freq = node->freq;
			freq_table[freq].erase(node);
			if(freq_table[freq].size() == 0) {
				freq_table.erase(freq);
				if (minfreq == freq)
					minfreq += 1;
			}
			freq_table[freq + 1].push_front(Node(key, value, freq + 1));
			key_table[key] = freq_table[freq + 1].beign();
		}
	}
};
//Time O(1) Space O(capacity)

355. 设计推特

题目链接

/*哈希表 + 链表*/
class Twitter {
	struct Node {
		unordered_set<int> followee;	//
		list<int> tweet;
	};
	int recentMax, time;
	unordered_map<int, int> tweetTime;
	unordered_map<int, Node> user;

public:
	Twitter() {
		time = 0;
		recentMax = 10;
		user.clear();
	}
	void init(int userId) {
		user[userId].followee.clear();
		user[userId].tweet.clear();
	}
	void postTweet(int userId, int tweetId) {{
		if (user.find(userId) == user.end()) 
			init(userId);
		if (user[userId].tweet.size() == recentMax)
			user[userId].tweet.pop_back();
		user[userId].tweet.push_front(tweetId);
		tweetTime[tweetId] = ++time;
	}
	vector<int> getNewsFeed(int userId) {
		vector<int> ans; ans.clear();
		for (list<int>::iterator it = user[userId].tweet.begin(); it != user[userId].tweet.end(); ++it) 
			ans.emplace_back(*it);
		for (int folleewId : user[userId].followee) {
			if (followeeId == userId) continue;
			vector<int> res; res.clear();
			list<int>::iterator it = user[followee].tweet.begin();
			int i = 0;
			while (i < (int)ans.size() && it != user[followeeId].tweet.end()) {
				if (tweetTime[(*it)] > tweetTime[ans[i]]) {
					res.emplace_back(*it);
					++it;
				}
				else {
					res.emplace_back(ans[i]);
					++i;
				}
				if ((int)res.size() == recentMax) break;
			}
			for (; i < (int)res.size() && (int)res.size() < recentMax; i++)
				res.emplace_back(ans[i]);
			for(; it != user[followeeId].tweet.end() && (int)res.size() < recentMax; ++it)
				res.empace_back(*it);
			ans.assign(res.begin(), res.end());
		}
		return ans;
	}
	void follow(int followerId, int followeeId) {
		if (user.find(followerId) == user.end())	
			init(followerId);
		if (user.find(followeeId) == user.end())	
			init(followeeId);
		user[followerId].followee.insert(followeeId);
	}
	void unfollow(int followerId, int followerId) {
		user[followerId].followee.erase(followeeId);
	}
};						
/*面向对象*/
int global_time = 0;

class Tweet {								//推文类
public: 
	int id;
	int time;
	Tweet *next;
	
	Tweet(int id) {
		this->id = id;
		this->time = global_time++;
		next = nullptr;
	}
};

class User {								//y用户类
public:
	int id;
	Tweet *tweet;
	unordered_set<int> follows;

	User(int id) {
		this->id = id;
		tweet = nullptr;
	}
	void follow (int followeeId) {
		if (followeeId == id) return ;
		follows.insert(followeeId);
	}
	void unfollow(int followeeId) {
		if (!follows.count(followeeId) || followeeId == id) return;
		follows.erase(followeeId);
	}
	void post(int tweetId)
		Tweet *newTweet = new Tweet(tweetId);
		newTweet->next = tweet;
		tweet = newTweet;
	}
};

class Twitter {
private:
	unordered_map<int, User*> user_map;
	
	bool contain(int id) {
		return user_map.find(id) != user_map.end();
	}

public:
	Twitter() {
		user_map.clear();
	}
	void postTweet(int userId, int tweetId) {
		if (!contain(userId))
			user_map[userId] = new User(userId);
		user_map[userId] = new User(userId);
	}
	vector<int? getNewsFeed(int userId) {
		if(!contain(userId)) return {};
		struct cmp {
			bool operator()(const Tweet *a, const Tweet *b) {
				return a->time < b->time;
			}			
		};
		
		priority_queue<Tweet*, vector<Tweet*>, cmp> q;

		if (user_map[userId]->tweet) 
			q.push(user_map[userId]->tweet);
		for(int followeeId : user_map[userId]->follows) {
			if(!contain(followeeId) continue;
			Tweet *head = user_map[followeeId]->tweet;
			if (!head) continue;
			q.push(head);
		}
		vector<int> rs;
		while(!q.empty()) {
			Tweet *t = q.top();
			q.pop();
			rs.push_back(t->id);
			if (rs.size() == 10) return rs;
			if (t->next) q.push(t->next);
		}
		return rs;	
	}
	
	void unfollow(int followerId, int followeeId) {
		if(!contain(followerId)) return;
		user_map[followerId]->unfollow(followeeId);
	}
};		

1472. 设计浏览器历史记录

题目链接

class BrowerHistory {
private:
	int pos, top;
	string history[5001];

public:
	BrowserHistory(string page): pos(-1), top(0) {
		visit(page);
	}	

	void visit(string url) {
		pos++;
		top = pos;
		history[top++] = url;
	}

	string back(int steps) {
		if (steps > pos) 
			steps = pos;
		pos -= steps;
		return history[pos];
	}
	
	string forward(int steps) {
		steps = min(steps, top - pos - 1);
		pos += steps;
		return history[pos];
	}
};		

622.设计循环队列

题目链接

/*数组*/
class MyCircularQueue {
private:
	int front;
	int rear;
	int capacity;
	vector<int> elements;

public:
	MyCircularQueue(int k) {
		this->capacity = k + 1;
		this->elements = vector<int> (capacity);
		rear = front = 0;
	}
	
	bool enQueue(int value) {
		if(isFull()) 
			return false;
		elements[rear] = value;
		rear = (rear + 1) % capacity;
		return true;
	}

	bool deQueue(int value) {
		if (isEmpty()) 
			return false;
		front = (front + 1) % capacity;
		return true;
	}
	
	int Front() {
		if (isEmpty()) 
			return -1;
		return elements[front];
	}
	
	int Rear() {
		if (isEmpty())
			return -1;
		return elements[(rear - 1 + capacity) % capacity];
	}

	bool isEmpty() {
	 	return rear == front;
	}
	
	bool isFull() {
		return ((rear + 1) % capacity) == front;
	}
};		
/*链表*/
class MyCircularQueue {
private:
	ListNode *head;
	ListNode *tail;
	int capacity;
	int size;

public:
	MyCircularQueue(int k) {
		this->capacity = k;
		this->size = 0;
		this->head = this->tail = nullptr;
	}
	
	bool enQueue(int value) {
		if (isFull())
			return false;
		ListNode *node = new LisNode(value);
		if (!head) 
			head = tail = node;
		else{
			tail->next = node;
			tail = node;
		}
		size++;
		return true;
	}
	
	bool deQueue() {
		if (isEmpty())
			return false;
		ListNode *node = head;
		head = head->next;
		size--;
		delete node;
		return true;
	}

	int Front() {
		if (isEmpty()) 
			return -1;
		return head->val;
	}

	int Rear() {
		if (isEmpty())
			return -1;
		return tail->val;
	}

	int isEmpty() {
		return size == 0;
	}

	int isFull() {
		return size == capacity;
	}
};

641. 设计循环双端队列

题目链接

/*数组实现*/
class MyCircularDeque {
private:
	vector<int> element;
	int front, rear, capacity;

public:
	MyCircularDequeue(int k) {
		this->capacity = k;
		this->element = vector<int> (capacity);
		rear = front = 0;
	}
	
	bool insertFront(int value) {
		if (isFull()) 
			return false;
		front = (front - 1 + capacity) % capacity;
		element[front] = value;
		return true;
	}
	
	bool insertLast(int value) {
		if (isFull())
			return false;
		element[rear] = value;
		rear = (rear + 1) % capacity;
		return true;
	}
	
	bool deleteFront() {
		if (isEmpty())
			return false;
		front = (front + 1) % capacity;
		return true;
	}
	
	bool deleteLast() {
		if (isEmpty())
			return false;
		rear = (rear - 1 + capacity) % capacity;
		return true;
	}

	int getFront() {
		if (isEmpty()) 
			return -1;
		return element[front];
	}

	int getLast() {
		if (isEmpty())
			return false;
		return element[(rear - 1 + capacity) % capcity];
	}

	bool isEmpty() {
		return rear == front;
	}

	bool isFull() {
		return (rear + 1) % capacity == front;
	}
};
/**
 * Your MyCircularDeque object will be instantiated and called as such:
 * MyCircularDeque* obj = new MyCircularDeque(k);
 * bool param_1 = obj->insertFront(value);
 * bool param_2 = obj->insertLast(value);
 * bool param_3 = obj->deleteFront();
 * bool param_4 = obj->deleteLast();
 * int param_5 = obj->getFront();
 * int param_6 = obj->getRear();
 * bool param_7 = obj->isEmpty();
 * bool param_8 = obj->isFull();
 */

705. 设计哈希集合

题目链接

  • 实现哈希集合这一数据结构需要解决以下几个关键问题
    1. 哈希函数:能够将集合任意可能的元素映射到一个固定范围的整数值,并将该元素存储到整数值对应的地址上。
    2. 冲突解决:由于不同元素可能映射相同的整数值。
      ~ 链地址法:为每一个哈希值维护一个链表,并将具有相同哈希值的元素都存放在这一链表中。
      ~ 开放地址法:当发现哈希值 h 处存在冲突时,根据某种策略,从 h 出发寻找下一个不冲突的位置。
      ~ 再哈希法:当发生哈希冲突后,使用另一个哈希函数产生新的地址。
    3. 扩容:当哈希表元素过多,冲突概率将越来越大,而在哈希表中查询一个元素的效率也会越来越低。因此需要开辟一块更大的空间来环节哈希表中的冲突。
/*链地址法*/
class MyHashSet {
private:	
	vector<list<int>> data;		 	//地址下链表(实际是个矩阵)
	static const int base = 769;   	//设计简单哈希函数 hash(x) = x mod base , 769质数
	static int hash(int key) {
		return key % base;
	}

public:
	MyHashSet(): data(base) {}

	void add(int key) {
		int h = has(key);
		for (auto it = data[h].begin(); it != data[h].end(); it++) {
			if((*it) == key)
				return;
		}
		data[h].push_back(key);
	}
	
	void remove(int key) {
		int h = hash(key);
		for (auto it = data[h].begin(); it != data[h].end(); it++) {
			if((*it) == key) {
				data[h].erase(it);
				return;
			}
		}
	}

	bool contains(int key) {
		int h = hash(key);
		for (auto it = data[h].begin(); it != data[h].end(); it++) {
			if ((*it) == key)
				return true;
		}
		return false;
	}
};

706. 设计哈希映射

题目链接

class MyHashMap{
private:
	vector<list<pair<int, int>>> data;
	static const int base = 769;
	static int hash(int key) {
		return key % base;
	}
public:
	MyHashMap(): data(base) {}

	void put(int key, int value) {
		int h = hash(key);
		for (auto it = data[h].begin(); it != data[h].end(); it++) {
			if ((*it).first == key) {
				(*it).second = value;
				return;
			}
		}
		data[h].push_back(make_pair(key, value));
	}

	void remove(int key) {
		int h = hash(key);
		for (auto it = data[h].begin(); it != data[h].end(); it++) {
			if((*it).first == key) {
				data[h].erase(it);
				return;
			}
		}
	}

	void get(int key) {
		int h = hash(key);
		for (auto it = data[h].begin(); it != data[h].end(); it++) {
			if ((*it).first == key) 
				return (*it).second;
		}
		return -1;
	}
};

707. 设计链表

题目链接

/*单链表*/
class MyLinkedList {
private:
	struct ListNode {
		int val;
		ListNode *next;
		ListNode(int x): val(x), next(nullptr) {}
	};
	
	ListNode *head;

public:
	MyLinkedList():head(nullptr) {}

	int get(int index) {
		ListNode *cur = head;
		for (int i = 0; cur && i <index; cur = cur->next, i++);
		if (cur) return cur->val;
		else return -1;
	}
	//Time O(index)
	
	void addAtHead(int val) {
		ListNode *node = new ListNode(val);
		node->next = head;
		head= node;
	}
	//Time O(1)

	void addAtTail(int val) {
		ListNode *node = new ListNode(val);
		if (!head) {
			head = node;
			return;
		}
		ListNode *cur = head;
		while (cur->next)
			cur = cur->next;
		cur->next= node;
	}
	//Time O(n)
		
	void addAtIndex(int index, int val) {
		ListNode *node = new ListNode(val);
		if (index <= 0) {
			addAtHead(val);
			return;
		}
		ListNode *cur = head;
		for (int i =0; i < index -1 && cur; cur = cur->next, ++i);
		if (cur) {
			node->next = cur->next;
			cur->next = node;	
		}
		return;
	}
	//Time O(index)
	
	void deleteAtIndex(int index) {
		if (index == 0 && head) {
			ListNode *del = head;
			head = head->next;
			delete del;
			return;
		}
		ListNode *cur = head;
		for (int i = 0; cur && i < index - 1; cur = cur->next, i++);
		if (!cur) return;
		if (cur->next) {
			ListNode *del = cur->next;
			cur->next = del->next;
			delete del;
		}
	}
	//Time O(index)
};	
/*双链表(虚拟头尾双结点)*/
class MyLinkedList{
private: 
	struct ListNode {
		int val;
		ListNode *prev, *next;
		ListNode() : val(0), prev(nullptr), next(nullptr) {}
		ListNode(int x) : val(x), prev(nullptr), next(nullptr) {}
		ListNode(int x, ListNode *p) : val(x), prev(p), next(nullptr) {}
		ListNode(int x, ListNode *p, ListNode *q) :val(x), prev(p), next (q) {}
	};

public:
	int size;
	ListNode *head, *tail;

	MyLinkedList() {
		size = 0;
		head = new ListNode(), tail = new ListNode();
		head->next = tail, tail->prev = head;
	}	
	
	int get(int index) {
		if(index < 0 || index >= size) return -1;
		ListNode *trav = head;
		if (2 * index < size - 1)
			for (int i = 0; i < index + 1; i++, trav = trav->next);
		else {
			trav = tail;
			for (int i = 0; i < size -index; ++i, trav = trav->prev);
		}
		return trav->val;
	}	
		
	void addAtHead(int val) {
		ListNode *node = new ListNode(val, head, head->next);
		node->next->prev = node;
		head->next = node;
		size++;
	}

	void addAtTail(int val) {
		ListNode* node = new ListNode(val, tail->prev, tail);
		tail->prev->next = node;
		tail->prev = node;
		++size;
	}

	void addAtIndex(int index, int val) {
		if(index > size) return ;
		ListNode *trav = head;
		if (index + 1 < size -index)
			for (int i = 0; i < index + 1; i++, trav = trav->next);
		else{
			trav = tail;
			for (int i = 0; i < size - index; i++, trav = trav->prev);
		}
		size++;
		ListNode *node = new ListNode(val, trav->prev, trav);
		trav->prev->next = node;
		trav->prev = node;
 	}

	void deleteAtIndex(int index) {
		if (index < 0 || index >= size) return ;
		ListNode *trav = head;
		if (index + 1 < size - index) 
			for(int i = 0; i < index + 1; i++, trav = trav->next);
		else{
			trav = tail;
			for (int i = 0; i < size - index; i++, trav = trav->prev);
		}	
		trav->prev->next = trav->next;
		trav->next->prev = trav->prev;
		delete trav;
		--size;
	}
};
/*双链表(虚拟头尾双结点)version2:较为简单的初始化*/
class MyLinkedList{
private:
	struct ListNode{
		int val;
		ListNode *next, *prev;
        ListNode(): val(0), next(nullptr), prev(nullptr) {}
		ListNode(int x): val(x), next(nullptr), prev(nullptr) {}
	};
  
    ListNode *head, *tail;
    int size = 0;

public:

	MyLinkedList() { 
        head = new ListNode(0);
        tail = new ListNode(0);
        head->next = tail;
        tail->prev = head;
    }

	int get(int index) {
		if (index < 0 || index >= size) return -1;
		ListNode *cur = head;
		if (index + 1 < size - index) 
			for (int i = 0; i < index + 1; ++i) cur = cur->next;
		else{
			cur = tail;
			for (int i = 0; i < size - index; ++i) cur = cur->prev;
		}
		return cur->val;
	}
	//O(min(index, n-index))
	
	void addAtHead(int val) {
		ListNode *succ = head->next, *pred = head;
		++size;
		ListNode *node = new ListNode(val);
		node->next = succ;
		node->prev = pred;
		pred->next = node;
		succ->prev = node;
	}
	//O(1)
	
	void addAtTail(int val) {
		ListNode *succ = tail, *pred = tail->prev;
		++size;
		ListNode *node = new ListNode(val);
		node->prev = pred;
		node->next = succ;
        succ->prev = node;
		pred->next = node;
	}
	//O(1)

	void addAtIndex(int index, int val) {
		if (index > size) return ;
		if (index < 0) index = 0;
		ListNode *pred, *succ;
		if (index < size -index) {
			pred = head;
			for (int i = 0; i < index; i++, pred = pred->next);
			succ = pred->next;
		}
		else {
			succ = tail;
			for (int i = 0; i < size - index; i++, succ = succ->prev);
			pred = succ->prev;
		}
		++size;
		ListNode *node = new ListNode(val);
		node->prev = pred;
		node->next = succ;
        pred->next = node;
		succ->prev = node;
	}
	//O(min(index, n-index))
	
	void deleteAtIndex(int index) {
		if (index < 0 || index >= size) return ;
		ListNode *pred, *succ;
		if (index < size - index) {
			pred = head;
			for (int i = 0; i < index; i++, pred = pred->next);
			succ = pred->next->next;
		}
		else {
			succ = tail;
			for (int i = 0; i < size - index - 1; i++, succ = succ->prev);
			pred = succ->prev->prev;
		}
		--size;
		pred->next = succ;
		succ->prev = pred;
	}
	//O(min(index, n-index))
};	

1206.设计跳表

constexpr int MAX_LEVEL = 32;
constexpr double P_FACTOR = 0.25;

struct SkiplistNode {
	int val;
	vector<SkiplistNode*> forward;				//一个结点存在着指向多层forward的指针,记录在vector里
	SkiplistNode(int _val, int _maxLevel = MAX_LEVEL): val(_val), forward(_maxLevel, nullptr) {}
}

class Skiplist {
private:
	SkiplistNode *head;
	int level;
	mt19937 gen{random_device{}()};
	uniform_real_distribution<double> dis;

public:
	Skiplist(): head(new SkiplistNode(-1)), level(0), dis(0,1) {}
	
	bool search(int target) {
		SkiplistNode *curr = this->head;
		//查找到第i层小于且最接近目标的元素
		for (int i = level - 1; i >= 0; i--) { 
			while (curr->forward[i] && curr->forward[i]->val < target)
				curr = curr->forward[i];
		}
		curr = curr->forward[0];		//到达最底层
		if (curr && curr->val == target)
			return true;
		return false;
	}	

	void add(int num) {
		vector<SkiplistNode *> update(MAX_LEVEL, head);
		SkoplistNode *curr = this->head;
		for (int i = level - 1; i >= 0; i--) {
			while (curr->forward[i] &&	curr->forward[i]->val < num) 
				curr = curr->forward[i];
			update[i] = curr;				//记录该层forward
		}

		int lv = randomLevel();
		level = max(level, lv);
		SkiplistNode *newNode = new SkiplistNode(num, lv);
		for (int i = 0; i < lv; i++) {
			newNode->forward[i] = update[i]->forwar[i];
			update[i]->forward[i] = newNode;
		}
	}

	bool erase(int num) {
		vector<SkiplistNode *> update(MAX_LEVEL, nullptr);
		SkiplistNode *curr = this->head;
		for (int i = level - 1; i >= 0; i--) {
			while (curr->forward[i] && curr->forward[i]->val < num)
				curr = curr->forward[i];
			update[i] = curr;
		}
		curr = curr->forward[0];
		if (!curr || curr->val != num)
			return false;
		
		for (int i = 0; i < level; i++) {
			if (update[i]->forward[i] != curr) 
				break;
			//对第i层状态进行更新,将forward指向被删除结点的下一跳
			update[i]->forward[i] = curr->forward[i];
		}
		delete curr;	
		//更新当前level
		while (level > 1 && head->forward[level - 1] == nullptr)
			level--;
		return true;
	}

	int randomLevel() {
		int lv = 1;
		while (dis(gen) < P_FACTOR && lv < MAX_LEVEL) 
			lv++;
		return lv;
	}
};			
//Time O(logn) Space O(n)	

1670. 设计前中后队列

题目链接

/*两个双端队列*/
//考虑情况:1.两队列均空2.首队列长度短一3.首次队列相等
class FrontMiddleBackQueue{
private:
	deque<int> deq1, deq2;

public:
	FrontMiddleBackQueue() {}
	
	void pushFront(int val) {
		deq1.push_front(val);
		int sz1 = deq1.size(), sz2 = deq2.size();
		if (sz1 > sz2) {				//当两个中间位置需要选择前一个位置,注定 size.deq1 <= size.deq2,平衡二者
			int temp = deq1.back();
			deq1.pop_back();
			deq2.push_front(temp);
		}
	}

	void pushMiddle(int val) {
		int sz1 = deq1.size(), sz2 = deq2.size();
		if (sz1 < sz2)
			deq1.push_back(val);
		else						//else sz1 == sz2
			deq2.push_front(val);
	}

	void pushBack(int val) {
		deq2.push_back(val);
		int sz1 = deq1.size(), sz2 = deq2.size();
		if (sz1 + 1 < sz2) {
			int temp = deq2.front();
			deq2.pop_front();
			deq1.push_back(temp);
		}
	}

	int popFront() {
		if (deq1.size() == 0) {
			if (deq2.size() == 0)
				return -1;
			else {
				int res = deq2.front();
				deq2.pop_front();
				return res;		
			}
		}
		else {
			int res = deq1.front();
			deq1.pop_front();
			int sz1 = deq1.size(), sz2 = deq2.size();
			if (sz1 + 1 < sz2) {
				int temp = deq2.front();
				deq2.pop_front();
				deq1.push_back(temp);
			}
			return res;
		}	
	}
	
	int popBack() {
		if (deq2.size() == 0) 
			return -1;
		int res = deq2.back();
		deq2.pop_back();
		int sz1 = deq1.size(), sz2 = deq2.size();
		if (sz1 > sz2) {
			int temp = deq1.back();
			deq1.pop_back();
			deq2.push_front(temp);
		}
		return res;
	}
	
	int popMiddle() {
		int sz1 = deq1.size(), sz2 = deq2.size();
		if (sz1 == 0 && sz2 == 0) return -1;
		if (sz1 < sz2) {
			int res = deq2.front();
			deq2.pop_front();
			return res;
		}
		else{
			int res = deq1.back();
			deq1.pop_back();
			return res;
		}
	}
};		

382. 链表随机结点

题目链接

/*数组记录链表所有元素*/
class Solution {
vector<int> arr;
public:
	Solution(ListNode *head){
		while(head) {
			arr.emplace_back(head->val);
			head = head->next;
		}
	}
	int getRandom() {
		return arr[rand() % arr.size()];
	}
};

/*Solution object will be instantiated and called as below*/
Solution *obj = new Solution(head);
int param_1 = obj->getRandom();

//Time: initialize O(n) getRand O(1),  Space O(n)
  • 水塘抽样: 大数据流中的随机抽样问题,即:当内存无法加载全部数据时,如何从包含未知大小的数据流中选取k个数据并且保证每个数据被抽到的概率相等。从链表头开始遍历整个链表,对于遍历到的第i个结点,随机选择 [ 0 , i ) [0,i) [0,i) 内的一个整数,如果其值等于0,则置该节点值为答案,否则答案不变。该算法保证每个结点的值成为最后被返回的值的概率均为 1 n \frac{1}{n} n1 ,证明如下:
    P ( 第 i 个结点成为最终返回值 ) = P ( 第 i 次随机值为0 ) × P ( 从第 i + 1 次到第 n 次随机数均不为 0 ) P(\text{第 i 个结点成为最终返回值})=P(\text{第 i 次随机值为0}) \times P(从第 i+1 次到第 n 次随机数均不为0) P( i 个结点成为最终返回值)=P( i 次随机值为0)×P(从第i+1次到第n次随机数均不为0)
    = 1 i × ( 1 − 1 i + 1 ) × . . . × ( 1 − 1 n ) = 1 i × i i + 1 × . . . × n − 1 n = 1 n =\frac{1}{i} \times (1-\frac{1}{i+1}) \times ... \times (1-\frac{1}{n}) = \frac{1}{i} \times \frac{i}{i+1} \times ...\times \frac{n-1}{n} = \frac{1}{n} =i1×(1i+11)×...×(1n1)=i1×i+1i×...×nn1=n1
/*水池抽样*/
class Solution {
	ListNode *head;
public: 
	Solution(ListNode *head) {
		this->head = head;
	}
	int getRandom() {
		int i = 1, ans = 0;
		for (ListNode node = head; node; node = node->next){
			if (rand() % i == 0)
				ans = node->val;
			++i;
		}
		return ans;
	}
};		
//Time: initialize O(1) getRand O(n), Space O(1) 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值