
class Solution {
public:void quickPartition(vector& nums, int start, int end, int target) {// 随机取一个数作为基准int random = (end - start) + start;int base = nums[random];// 将该数放到待快排区间开头第一个元素swap(nums[start], nums[random]);int index = start;// 从待快排区间的第二个元素开始,依次与base比较,如果大于等于base则将该元素// 交换到index + 1位置,index++,使得最终index前面的元素都比base大。for (int i = start + 1; i <= end; ++i) {if (nums[i] >= base) {swap(nums[index + 1], nums[i]);index++;}}// base存放在区间开头,现在需要把它交换到index位置,这就是它在整个有序数组中的位置。swap(nums[index], nums[start]);// 如果index小于target,需要在右边区间继续快排查找,否则到在边区间查找,// 如果等于已经找到目标值不需要递归,这里这么做优化了传统快排的复杂度。if (index < target) {quickPartition(nums, index + 1, end, target);}else if (index > target) {quickPartition(nums, start, index - 1, target);}}int findKthLargest(vector& nums, int k) {// 方法1. 快速排序的分区思想,快排的思想是一次找出一个数的正确位置,// 并使得该数左边的元素都比它小,该数右边的元素都比它大,要找出第k// 大的元素,只需要在快排的时候采用降序排序,找到下标为k-1的元素即可。quickPartition(nums, 0, nums.size() - 1, k - 1);return nums[k - 1];}
};
class Solution {
public:ListNode* reverseKGroup(ListNode* head, int k) {if (k <= 1)//首先判断k的合法性return head;stack myStack;//辅助栈,用于转换k个节点的转换int count = 0;//进栈的节点数ListNode *ptr = head;//进栈k个节点while (count < k && ptr != NULL){myStack.push(ptr);ptr = ptr->next;++count;}if (count < k){//如果不足k个,则无需转换return head;}//出栈并且顺序串接好//pHead是逆置结果的表头,pEnd是逆置结果的临时表尾ListNode *pHead = myStack.top(), *pEnd;myStack.pop();pEnd = pHead;while (count > 1){pEnd->next = myStack.top();pEnd = pEnd->next;myStack.pop();--count;}//递归调用,将ptr后面的链表进行逆置pEnd->next = reverseKGroup(ptr, k);return pHead;}
};
思路:可以把整段链表分为
class Solution {
public:ListNode* reverseKGroup(ListNode* head, int k) {if (!head) {return head;}int loop = 0; //计数第几个节点,用于判断是否ListNode* p = head; ListNode* pHead = p;ListNode* pLast = p;while (p) {++loop;if (loop % k == 0) {ListNode* temp = reverse(pHead, p);if (loop == k) {head = temp; //第一次到达k时,此时返回的head就是最终的head} else {pLast->next = temp; //非第一次到达k时,把刚反转的那一段链表的头节点接到上一次已反转的尾部}p = pHead;pHead = p->next;pLast = p;}p = p->next;}return head;}ListNode* reverse(ListNode* head, ListNode* last) { //给定一个头节点一个尾节点,反转链表ListNode* realhead = last->next; //把未到达的那个节点连接到尾部,便于后面正常遍历while (realhead != last) {ListNode* p = head->next;head->next = realhead;realhead = head;head = p;}return realhead;}
};
class Solution {
public:int maxProfit(vector& prices) {int maxAns = 0;int minPrice = 99999;for (int i = 0; i < prices.size(); i++) {minPrice = min(minPrice, prices[i]); maxAns = max(maxAns,prices[i] - minPrice);}return maxAns;}
};
class Solution {
public:int maxProfit(vector& prices) {int maxP = 0;for (int i = 1; i < prices.size(); i++) {maxP += max(0, prices[i] - prices[i-1]);}return maxP;}
};
class Solution {
public:int lengthOfLongestSubstring(string s) {unordered_map map; //int left = 0, size = s.length();int ans = 1, right = 1;map[s[left]] = 1;if (!size) {return 0;}while (right < size) {if (map.find(s[right]) != map.end()) { //如果遍历的这个字符在map里,把left位置的字符从map里删除,并right不动,left++ans = max(ans, right-left);map.erase(s[left]);++left;} else { //当遍历的这个字符不存在map里,就往后走,并把该字符添加到map里map[s[right]] = 1;++right;}}ans = max(ans, right-left);return ans;}
};
维护dp数组里的最大值
维护已遍历原数组里最大值,每次与最大值比较,如果大于max,就让dp数组的该索引值为++max。否则还为max
class Solution {
public:int lengthOfLIS(vector& nums) {vector dp(nums.size(), 1);dp[0] = 1;int ans = 1;for (int i = 1; i < nums.size(); i++) {for (int j = 0; j < i; j++) {if (nums[i] > nums[j]) {dp[i] = max(dp[i], dp[j]+1);ans = max(ans, dp[i]);}}}return ans;}
};
利用一个hashmap,出现一次的保留在map里,出现第二次就从map里删除
class Solution {
public:vector singleNumber(vector& nums) {unordered_map map;vector ans;for (int i = 0; i < nums.size(); i++) {if (map.find(nums[i]) != map.end()) {map.erase(nums[i]);} else {map[nums[i]] = 1;}}for (auto& it : map) {ans.push_back(it.first);}return ans;}
};
struct linkList { //创建双向链表int key, value;linkList* next;linkList* prev;
};
class LRUCache {
public:int size;int capacity;linkList* head; //保留住头节点位置,头节点的下一个为最新的linkList* last; //保留尾节点,尾节点的上一个为最旧的unordered_map map;LRUCache(int capacity) { //初始化size = 0;this->capacity = capacity;head = new linkList;last = new linkList;head->next = last;last->prev = head;}int get(int key) {if (map.find(key) == map.end()) { //未找到return -1;} else {moveToFirstNode(map[key]); //移到头节点后面return map[key]->value;}}void put(int key, int value) { if (map.find(key) != map.end()) { //如果在map里找到了该key,就从value保存的节点修改值就好,然后再移到首部map[key]->value = value;moveToFirstNode(map[key]);return;}if (size < capacity) { //缓存够的话,直接放进首部map[key] = addNode(key, value);++size;} else {removeNode();map[key] = addNode(key, value); //缓存不够,需要移除尾节点,再把新添加的节点放到首部}}linkList* addNode(int key, int value) {linkList* p = new linkList; //设值p->value = value;p->key = key;head->next->prev = p; //头插法p->next = head->next;p->prev = head;head->next = p;return p;}void removeNode() { //移除最后一个节点linkList* pRemove = last->prev; linkList* temp = last->prev->prev;temp->next = last;last->prev = temp;map.erase(pRemove->key);delete pRemove;}void moveToFirstNode(linkList* p) { //把节点p从中间断开再放入首部linkList* temp = p->prev; //断开,并把分隔开的上下两个节点连接好linkList* pNext = p->next;temp->next = pNext;pNext->prev = temp;head->next->prev = p; //放到首部p->next = head->next;p->prev = head;head->next = p;}
};
我们需要维护当前每个链表没有被合并的元素的最前面一个,k 个链表就最多有 k 个满足这样条件的元素,每次在这些元素里面选取 val 属性最小的元素合并到答案中。在选取最小元素的时候,我们可以用优先队列来优化这个过程。
class Solution {
public:struct comp { // 重载运算符bool operator () (ListNode* a, ListNode* b) {return a->val > b->val;}};priority_queue, comp> q;ListNode* mergeKLists(vector& lists) {for (auto node: lists) {if (node) {q.push(node);}}ListNode* head = new ListNode();ListNode* tail = head;while (!q.empty()) {ListNode* node = q.top();q.pop();tail->next = node; tail = tail->next;if (node->next) {q.push(node->next);}}return head->next;}
};