算法题复习(快排、链表、二分、哈希、双指针)

目录

    • 1、快速排序复习
    • 2、链表部分复习
      • 203. 移除链表元素
      • 707. 设计链表
      • 206. 反转链表
      • 142.环形链表 II
    • 3、二分法复习
    • 4、哈希法复习
    • 5、双指针复习
      • **15. 三数之和**
      • **18. 四数之和**
      • **27. 移除元素**
      • **344. 反转字符串**,简单,双指针从两侧往中间靠拢,并随时swap
      • **剑指 Offer 05. 替换空格**
      • **151. 翻转字符串里的单词**

1、快速排序复习

基本思想:
1、在当前的排序序列中任意选取一个元素,把该元素称为基准元素或支点,把下雨等于基准元素的所有元素都移动到基准元素的前面,把大于基准元素的所有元素都移到基准元素的后面,这样使得基准元素所处的位置 恰好就是排序的最终位置,并且把当前参加排序的序列分为前后两个序列。
2、上述的过程称为一趟快速排序,即快速排序的一次划分
3、接下来分别对这两个子序列重复上述的排序操作(如果子序列长度大于1的话),直到所有元素都被移动到排序后他们应处的最终位置上。
效率之所以高:每一次元素的移动都是跳跃的,不会像冒泡排序只能在相邻元素之间进行,元素移动的间隔较大,因此总的比较和移动次数减少

具体步骤:

1、假设序列a,设置两个变量i、j.分别指向首元素和尾元素,设定i指向的首元素为基准元素

2、反复执行i++,直到i指向的元素>=基准元素,或者i指向尾部

3、反复执行j–,直到指向的元素<基准元素,或者j指向头部

4、若此时i<j,将i和j指向的元素进行交换。(大的元素在后面)

5、完成第一次交换后,重复执行步骤1、2,直到i>=j位置

6、此时i>=j,然后将基准元素与j指向的元素交换位置,至此完成了原序列的第一次划分

7、接下来分别对基准元素前后的子序列中长度大于1的子序列重复执行上述操作。

步骤分析:

对于每个子序列的操作又是一次划分,因此这个算法具有递归性质。

每次划分过程的基准元素仍可设定为子序列的第一个元素

#include<iostream>
#include <vector>
using namespace std;
//快速排序
void Quicksort(vector<int>& a, int s, int t)
{int i, j;if (s < t){//【1】设置两个变量i、j.分别指向首元素和尾元素,设定i指向的首元素为基准元素i = s;j = t + 1;while (1){do i++;while (!(a[s] <= a[i] || i == t));               //【2】重复i++操作,直到i指向的元素>=基准元素,或者i指向尾部do j--;while (!(a[s] >= a[j] || j == s));              //【3】反复执行j--,直到指向的元素<基准元素,或者j指向头部if (i < j)                                  //【5】若此时i<j,将i和j指向的元素进行交换。(大的元素在后面){swap(a[j], a[i]);}else break;                                  //【5】完成第一次交换后,重复执行步骤1、2,直到i>=j位置}//【6】此时i>=j,然后将基准元素与j指向的元素交换位置,至此完成了原序列的第一次划分swap(a[s], a[j]);//【7】接下来分别对基准元素前后的子序列中长度大于1的子序列重复执行上述操作。Quicksort(a, s, j - 1);                             //前半序列Quicksort(a, j + 1, t);                             //后半序列}
}
void show_sort_result(vector<int> a, int k)
{for (int f = 0;f < k;f++){cout << a[f] << "  ";}printf("\n");
}
int main()
{vector<int> a = { 98,76,109,34,67,190,80,12,14,89,1 };printf("快速排序\n");Quicksort(a,0,a.size() - 1);show_sort_result(a, a.size() - 1);return 0;
}

2、链表部分复习

链表定义

struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode *next) : val(x), next(next) {}
};

203. 移除链表元素

不使用虚拟头节点

class Solution {public:ListNode* removeElements(ListNode* head, int val) {//删除头节点while(head != nullptr && head->val == val){ListNode* temp = head;head = head->next;delete(temp);}//删除非头节点ListNode* cur = head;while(cur != nullptr && cur->next != nullptr){if(cur->next->val == val){ListNode* temp = cur->next;cur->next = cur->next->next;delete(temp);}else {cur = cur->next;}}return head;}
};

使用虚拟头节点:
注意如果使用指针的话,没有delete dummy会造成内存泄漏。


class Solution {public:ListNode* removeElements(ListNode* head, int val) {ListNode* dummyHead = new ListNode(0);dummyHead->next = head;ListNode* cur = dummyHead;while(cur->next != nullptr){if(cur->next->val == val){ListNode* temp = cur->next;cur->next = cur->next->next;delete temp;}else {cur = cur->next;}}ListNode* ret = dummyHead->next;delete dummyHead;return ret;}
};

707. 设计链表

注意虚拟头节点的使用。

class MyLinkedList {
public://定义链表的结构体struct ListNode {int val;ListNode* next;ListNode(int val) : val(val) , next(nullptr) {}};
private://定义链表的虚拟头节点ListNode* _dummyHead;int _size;
public:/** Initialize your data structure here. */MyLinkedList() {_dummyHead = new ListNode(0);_size = 0;  //记录链表中已经存在的元素个数}/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */int get(int index) {if(index < 0 || index > _size -1)return -1;ListNode* cur = _dummyHead->next;while(index--){cur = cur->next;}return (cur->val);}/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */void addAtHead(int val) {ListNode* newNode = new ListNode(val);newNode->next = _dummyHead->next;_dummyHead->next = newNode;_size++;}/** Append a node of value val to the last element of the linked list. */void addAtTail(int val) {ListNode* newNode = new ListNode(val);ListNode* cur = _dummyHead; //注意cur从_dummy开始,防止链表一开始为空while(cur->next != nullptr){cur = cur->next;}//此时cur->next为空cur->next = newNode;_size++;}/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */void addAtIndex(int index, int val) {if(index > _size) return ;if(index < 0){addAtHead(val);return ;} ListNode* newNode = new ListNode(val);ListNode* cur = _dummyHead;while(index--){cur = cur->next;}newNode->next = cur->next;cur->next = newNode;_size++;}/** Delete the index-th node in the linked list, if the index is valid. */void deleteAtIndex(int index) {if(index >= _size || index < 0){return ;}ListNode* cur = _dummyHead;while(index--)cur = cur->next;ListNode* temp = cur->next;cur->next = cur->next->next;delete temp;_size--;}
};/*** Your MyLinkedList object will be instantiated and called as such:* MyLinkedList* obj = new MyLinkedList();* int param_1 = obj->get(index);* obj->addAtHead(val);* obj->addAtTail(val);* obj->addAtIndex(index,val);* obj->deleteAtIndex(index);*/

206. 反转链表

注意while循环的条件以及最后返回的是pre。

class Solution {
public:ListNode* reverseList(ListNode* head) {ListNode* cur = head;ListNode* pre = nullptr;while(cur != nullptr){ListNode* temp = cur->next;cur->next = pre;pre = cur;cur = temp;}return pre;}
};

142.环形链表 II

在这里插入图片描述

数学推导:
相遇时:
slow走过节点数:x+y
fast走过节点数:x+y+n(y+z)
并且有:
(x+y)*2 = x+y+n(y+z)
当n= 1时,x = z:
即:
从头节点出发一个指针,从相遇节点也出发一个指针,这两个指针每次只走一个节点,那么当这两个指针相遇的时候就是环形入口的节点了。

class Solution {
public:ListNode *detectCycle(ListNode *head) {ListNode* fast = head;ListNode* slow = head;while(fast != nullptr && fast->next != nullptr) {slow = slow->next;fast = fast->next->next;//快慢指针相遇if(fast == slow){ListNode* index1 = fast;ListNode* index2 = head;while(index1 != index2){index1 = index1->next;index2 = index2->next;}return index2;}}return nullptr;}
};

3、二分法复习

二分法变种对于不完全有序的还需要再刷刷
在这里插入图片描述

4、哈希法复习

242. 有效的字母异位词
https://leetcode-cn.com/problems/valid-anagram/
349. 两个数组的交集,注意set的使用,还是不太熟悉
https://leetcode-cn.com/problems/intersection-of-two-arrays/
202. 快乐数
https://leetcode-cn.com/problems/happy-number/
1. 两数之和,注意map的使用,不是很熟悉,要熟悉map的insert操作
https://leetcode-cn.com/problems/two-sum/submissions/
454. 四数相加 II ,注意count加上的是该值上所有的频次。
https://leetcode-cn.com/problems/4sum-ii/submissions/
383. 赎金信,注意在map中加哪个减哪个。如果ransomNote中出现了magazine不存在的字母,则失败。
https://leetcode-cn.com/problems/ransom-note/

5、双指针复习

15. 三数之和

https://leetcode-cn.com/problems/3sum/
需要注意三个地方:
1、第一次去重,在外层for循环中,如果遇到相同的相邻元素continue
2、第二次去重,每一次找到一次三元组后也要进行一次去重,直到不再符合left < right
3、找到一个答案后,双指针同时收缩

class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {sort(nums.begin(),nums.end());vector<vector<int>> result;for(int i = 0; i < nums.size(); i++){if(nums[i] > 0) break;//第一次去重,在外层for循环中,如果遇到相同的相邻元素continueif(i > 0 && nums[i] == nums[i-1]) continue;int left = i + 1;int right = nums.size() - 1;while(left < right) //不能取={int tmp_sum = nums[i] + nums[left] + nums[right];if(tmp_sum > 0) right--;else if(tmp_sum < 0) left++;else {result.emplace_back(vector<int>{nums[i],nums[left],nums[right]});//第二次去重,每一次找到一次三元组后也要进行一次去重,直到不再符合left < rightwhile(left < right && nums[right - 1] == nums[right]) right--;while(left < right && nums[left] == nums[left + 1]) left++;//找到一个答案后,双指针同时收缩left++;right--;}}}return result;}
};

18. 四数之和

https://leetcode-cn.com/problems/4sum/
需要注意地方:
分为3重嵌套,比上一题多了一层循环。所以在最外层也多一个去重。
剪枝操作时错误的,不可以剪枝。
三数之和:

for{
剪枝;
去重;
while(再去重)}

四数之和:

for
{
去重;
for{去重;while(再去重)}
}

27. 移除元素

https://leetcode-cn.com/problems/remove-element/
重点在于fast每时每刻都在往后走(无论该元素是否==val),如果不等于的话slow也需要走。nums【fast】=val的时候slow不走,fast走。
接着到下一个 nums【fast】!=val时,将指向的元素向前移动。

class Solution {
public:int removeElement(vector<int>& nums, int val) {int slow = 0;for(int fast = 0; fast < nums.size(); fast++){if(nums[fast] != val){nums[slow] = nums[fast];slow++;}}return slow;}
};

344. 反转字符串,简单,双指针从两侧往中间靠拢,并随时swap

https://leetcode-cn.com/problems/reverse-string/

剑指 Offer 05. 替换空格

先计算扩充后大小,然后从后向前替换空格。数组填充类题均是这样做。
https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof/

class Solution {
public:string replaceSpace(string s) {int count = 0;  //记录空格数int old_size = s.size();for(int i = 0; i < old_size; i++){if(s[i] == ' ') count++;}//扩充ss.resize(old_size + count * 2);int new_size = s.size();//定义两个指针,指向两个位置int new_index = new_size - 1;int old_index = old_size - 1;while(old_index < new_index) {if(s[old_index] != ' '){s[new_index] = s[old_index];} else{s[new_index] = '0';new_index--;s[new_index] = '2';new_index--;s[new_index] = '%';}new_index--;old_index--;}return s;}
};

151. 翻转字符串里的单词

,这一题还得多做几遍。。
https://leetcode-cn.com/problems/reverse-words-in-a-string/
这一题对空格的处理操作更加繁琐一点;
思路:
1、移除多余空格
2、将整个字符串反转
3、将每个单词反转
如:
“the sky is blue” => “the sky is blue” => “eulb si yks eht” => “blue is sky the”
1、去除多余空格,使用双指针

void removeExtraSpaces(string& s){//定义快慢指针int slow = 0;int fast = 0;//去除字符串前面的空格while(s.size() > 0 && fast < s.size() && s[fast] == ' ') fast++;//去除字符串中间的荣誉空格while(fast < s.size()){if(fast > 1 && s[fast] == ' ' && s[fast - 1] == ' ') {fast++;continue;}else{s[slow] = s[fast];slow++;fast++;}}//去除字符串末尾的空格,并重新设置字符串大小if(slow > 1 && s[slow - 1] == ' '){s.resize(slow - 1);}else{s.resize(slow);}}

2、反转字符串,使用双指针

    void reverse(string& s,int left,int right) {while(left <= right){swap(s[left],s[right]);left++;right--;}}

3、将字符串中的每个单词反转

string reverseWords(string s) {removeExtraSpaces(s);reverse(s,0,s.size() - 1);int fast = 0; int slow = 0;while(fast < s.size()){//如果遍历到字符串中间一个单词结束if(s[fast] == ' '){reverse(s,slow,fast - 1);//跳过空格slow = fast + 1;}//如果遍历到最后一个单词结束(此时没有空格)if(fast == s.size() -1){reverse(s,slow,fast);}fast++;}return s;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/377329.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cassandra1.2文档学习(7)—— 规划集群部署

数据参考&#xff1a;http://www.datastax.com/documentation/cassandra/1.2/webhelp/index.html#cassandra/architecture/architecturePlanningAbout_c.html 当规划一个Cassandra集群部署时&#xff0c;关于你初始存储的数据的数据量你应当有一个好的想法&#xff0c;并且对于…

虚拟机设置NAT

需要开启虚拟机网络相关服务&#xff0c; 安装虚拟网卡&#xff0c; 还有必须安装 VMware ToolsVMware虚拟机下实现NAT方式上网1. 把你的虚拟网卡VMnet8设置为自动获得IP、自动获得DNS服务器&#xff0c;启用。2. 把你虚拟机中操作系统的“本地连接”也设置为自动获得IP、自动获…

窗体震动 C# (不使用Timer控件,控制窗体震动)

private static Point plocation new Point(); public static void StartVibration(Form form)//Form 传入需要振动的窗体 { plocation form.Location; for (int i 1; i < 41; i)//41&#xff0c;可以理解为震动的时间。…

算法题复习(栈与队列、二叉树)

目录栈与队列栈用于匹配的问题队列用于堆二叉树系列深度遍历&#xff0c;递归与迭代层序遍历二叉树属性二叉树修改与构造二叉搜索树公共祖先二叉搜索树的修改与构造栈与队列 栈用于匹配的问题 20. 有效的括号 https://leetcode-cn.com/problems/valid-parentheses/ 不匹配的三…

bpsk_BPSK的完整形式是什么?

bpskBPSK&#xff1a;二进制相移键控 (BPSK: Binary Phase Shift Keying) BPSK is an abbreviation of "Binary Phase Shift Keying". BPSK是“二进制相移键控”的缩写 。 BPSK is also occasionally called phase reversal keying (PRK), or 2PSK, which is the el…

win7 下安装oracle 10g

oracle 10g 在win7下安装&#xff0c;提示程序异常终止&#xff0c;发生未知错误 在网上搜结果&#xff1a; 修改Oracle 10G\database\stage\prereq\db\refhost.xml 在 </SYSTEM> <CERTIFIED_SYSTEMS>后面添加 <!--Microsoft Windows 7--> <OPERAT…

poj 1703 Find them, Catch them

题目链接&#xff1a;http://poj.org/problem?id1703 题目大意&#xff1a;警察抓获N个罪犯&#xff0c;这些罪犯只可能属于两个团伙中的一个&#xff0c;现在给出M个条件&#xff08;D a b表示a和b不在同一团伙&#xff09;&#xff0c;对于每一个询问(A a b)确定a&#xff0…

双向a*搜索算法_双向搜索算法

双向a*搜索算法什么是双音搜索&#xff1f; (What is bitonic search?) Searching a bitonic array is known as bitonic search. An array is said to be bitonic if it has an increasing sequence of integers followed immediately by a decreasing sequence of integers.…

关于LRU缓存简单记录以及代码补全。

目录大概思路时间空间复杂度分析指针操作具体细节代码双向链表设计私有成员变量设计:构造函数和析构函数设计&#xff1a;get与put具体设计双向指针的具体细节添加到头节点函数删除尾节点函数删除节点函数删除节点函数感想今天面试考到LRU&#xff0c;太紧张了&#xff0c;完全…

码农干货系列【4】--图像识别之矩形区域搜索

简介 定位某个图片的矩形区域是非常有用的&#xff0c;这个可以通过手动的选择某个区域来实现定位&#xff0c;图片相关的软件都提供了这个功能&#xff1b;也可以像本篇一个通过程序来实现智能定位。前者会有误差&#xff0c;效率低下&#xff1b;后者选区精度高&#xff0c;效…

算法题复习(回溯)

目录base code棋盘问题51. N 皇后37. 解数独组合问题77. 组合未剪枝优化剪枝优化216. 组合总和 III未剪枝优化剪枝优化17. 电话号码的字母组合39. 组合总和未剪枝优化剪枝优化40. 组合总和 II,挺重要的&#xff0c;涉及到去重了切割问题131. 分割回文串子集问题78. 子集90. 子集…

pfa是什么意思_PFA的完整形式是什么?

pfa是什么意思PFA&#xff1a;预测性故障分析 (PFA: Predictive Failure Analysis) PFA is an abbreviation of Predictive Failure Analysis. It is a technique of a mechanism of the computer that is used to predict impending failures of software or hardware compone…

SqlServer视图(view)

--上节回顾--1.什么是事务--2.事务的特征--原子性、一致性、隔离性、持久性--3.与事务相关的t-sql命令--开启事务&#xff1a;begin transaction--提交事务&#xff1a;commit transaction--回滚事务&#xff1a;rollback transaction ----------------视图-------------------…

Android中的广播Broadcast详解

今天来看一下Android中的广播机制&#xff0c;我们知道广播Broadcast是Android中的四大组件之一&#xff0c;可见他的重要性了&#xff0c;当然它的用途也很大的&#xff0c;比如一些系统的广播&#xff1a;电量低、开机、锁屏等一些操作都会发送一个广播&#xff0c;具体的And…

sql check约束_在SQL中使用CHECK约束

sql check约束Basically, CHECK constraint is used to LIMIT in columns for the range of values. We can use this constraint for single or multiple columns. 基本上&#xff0c; CHECK约束用于限制值范围内的列 。 我们可以将此约束用于单列或多列。 In single column,…

.NET线程池

摘要 深度探索 Microsoft .NET提供的线程池&#xff0c; 揭示什么情况下你需要用线程池以及 .NET框架下的线程池是如何实现的&#xff0c;并告诉你如何去使用线程池。 内容 介绍 .NET中的线程池 线程池中执行的函数 使用定时器 同步对象的执行 异步I/O操作 监视线程池 死锁 有关…

折线分割平面

Input输入数据的第一行是一个整数C,表示测试实例的个数&#xff0c;然后是C 行数据&#xff0c;每行包含一个整数n(0<n<10000),表示折线的数量。Output对于每个测试实例&#xff0c;请输出平面的最大分割数&#xff0c;每个实例的输出占一行。Sample Input2 1 2Sample Ou…

《c++特性》

目录多态构造函数和析构函数存在多态吗&#xff1f;虚函数表虚析构函数纯虚函数和抽象类运行时多态和编译时多态的区别继承设计实例指针对象和普通对象的区别正确初始化派生类方式继承和赋值的兼容规则protected 和 private 继承基类与派生类的指针强制转换如何用C实现C的三大特…

Scala中的while循环

在Scala中的while循环 (while loop in Scala) while loop in Scala is used to run a block of code multiple numbers of time. The number of executions is defined by an entry condition. If this condition is TRUE the code will run otherwise it will not run. Scala中…

Linux操作系统启动过程

在做开发的过程中&#xff0c;突然发现&#xff0c;要对系统做一些有意义的改变&#xff0c;必须要对操作系统的启动过程有一定的了解&#xff0c;不然就是修改你都不知道从哪里下手啊&#xff0c;然后就是找来资料看&#xff0c;去网上看别人的博客&#xff0c;有了前一周一些…