常见的几种算法整理
- 二分法查找/搜索
- 贪心算法
- Dp动态规划
- KMP查找子串
- Hash的使用
- sort排序函数的使用
- priority_queue(大堆/小堆队列使用)
二分法查找/搜索
题目:给定一个排序的数组(升序)和一个要查找的整数target,用二分法找到target第一次出现的下标(从0开始)
重点: 使用while (begin + 1 < end)来结束循环,然后对当前的begin与end进行判断
int binarySearch(vector<int>& nums, int target) {
int begin = 0;
int end = nums.size() - 1;
int middle;
if ((target < nums[begin]) || (target > nums[end]))
return -1;
while (begin + 1 < end) {
middle = (end + begin) / 2;
if (target > nums[middle])
begin = middle;
else
end = middle;
}
if (nums[begin] == target)
return begin;
if (nums[end] == target)
return end;
return -1;
}
贪心算法
题目:给定一个整数数组,找到一个具有最大和的子数组,返回其最大和
思想:每次都尽可能拿到当前最大的值,对比上一次结果。
int maxSubArray(vector<int>& nums) {
int result = INT_MIN;
int sum = 0;
for (int i = 0; i < nums.size(); i++) {
sum = sum + nums[i];
result = max(sum, result); //贪心到最大
sum = max(sum, 0); //当前的最大值
}
return result;
}
Dp动态规划
题目:给定一个只含非负整数的m*n网格,找到一条从左上角到右下角的可以使数字和最小的路径
思想: grid[i][j]代表节点值, f[i][j]代表从 (0,0)到(i,j)的最短路径
f[0][0] = grid[0][0]; //初始值
f[i][0] = f[i - 1][0] + grid[i][0]; //第一列的值
f[0][i] = f[0][i - 1] + grid[0][i]; //第一行的值
f[i][j] = min(f[i - 1][j], f[i][j - 1]) + grid[i][j]; //其他节点的值
当i=m-1, j=n-1时,即为结果
int minPathSum(vector<vector<int>>& grid) {
if ((grid.size() == 0) || (grid[0].size() == 0))
return 0;
int m = grid.size();
int n = grid[0].size();
int f[1000][1000];
f[0][0] = grid[0][0];
for (int i = 1; i < m; i++) {
f[i][0] = f[i - 1][0] + grid[i][0];
}
for (int i = 1; i < n; i++) {
f[0][i] = f[0][i - 1] + grid[0][i];
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
f[i][j] = min(f[i - 1][j], f[i][j - 1]) + grid[i][j];
}
}
return f[m - 1][n - 1];
}
KMP查找子串
KMP算法实现查找子串 时间复杂度O(m+n),空间复杂度O(n)
思想:KMP算法实现原理
class KMPStringSeek{
public:
/**
* @param source:
* @param target:
* @return: return the index
*/
//KMP算法
int strStr(string& source, string& target) {
int i = 0, j = 0;
int source_len = source.length();
int target_len = target.length();
vector<int> next(target_len+1);
getNext(target, next);
while (i < source_len && j < target_len)
{
if (j == -1 || source[i] == target[j])
{
i++;
j++;
} else {
j = next[j];
}
}
if (j == target_len)
return i - j;
else
return -1;
return 0;
}
//计算next数组
void getNext(string target, vector<int>& next)
{
next[0] = -1;
int i = 0, j = -1, target_len = target.length();
while (i < target.length())
{
if (j == -1 || target[i] == target[j])
next[++i] = ++j;
else
j = next[j];
}
}
};
Hash的使用
题目:给定一个整数数组,找到和为0的子数组。返回子数组的起始位置和结束位置
思想:使用hash表,利用维护前缀和来实现。优化时间复杂度,提高效率
1. 定义一个整型变量sum记录当前的前缀和,定义一个hash表,hash[sum]=i表示sum这个值是第i个位置的前缀和
2. 初始化:sum = 0, hash[0] = -1;(该定义代表数组-1的位置值为0)
3. 循环遍历这个整数数组,对于当前位置i,进行如下操作:
sum累加, 到hash里面寻找sum,找到则返回区间值,结束;否则hash[sum] = i,继续查找
vector<int> subarraySum(vector<int>& nums) {
unordered_map<int, int> hash; //快速hash查找
vector<int> result;
int sum = 0;
int size = nums.size();
hash[0] = -1;
for (int i = 0; i < size; i++) {
sum += nums[i];
//如果sum在hash里面,即上一个sum与这一个sum区间和为0
if (hash.find(sum) != hash.end()) {
result.push_back(hash[sum] + 1);
result.push_back(i);
}
hash[sum] = i;
}
return result;
}
sort排序函数的使用
题目:给定一系列的会议时间间隔,包括起始和结束时间[[s1,e1],[s2,e2],…(si < ei),确定一个人是否可以参加所有会议
思想:对会议起始时间s1…si进行排序,重新得到数组。然后依次顺序比较,当si<e(i-1)时,返回false。
看一下sort的定义:
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
- 第一个参数first:是要排序的数组的起始地址。
- 第二个参数last:是结束的地址(最后一个数据的后一个数据的地址)
- 第三个参数comp是排序的方法:可以是从升序也可是降序。如果第三个参数不写,则默认的排序方法是从小到大排序。
//固定写法,升序排列
static bool cmp(const Interval& v1, const Interval& v2) {
return v1.start < v2.start; //按start进行升序排列
}
bool canAttendMeetings(vector<Interval>& intervals) {
//排序
sort(intervals.begin(), intervals.end(), cmp);
//维护终点的最大值
int maxend = -1;
for (int i = 0; i < intervals.size(); i++) {
if (intervals[i].start < maxend) {
return false;
}
maxend = max(maxend, intervals[i].end);
}
return true;
}
priority_queue(大堆/小堆队列使用)
题目:给定一个未排序的整数数组,找到其中位数
思想:使用小堆队列,即进入队列的数据会进行排序,队头为最大值。根据数组长度得到中位数的位置pos,向queue中push数据,达到pos大小时停止,之后做比较,一直改变最顶值即可。
int median(vector<int>& nums) {
// write your code here
int size = nums.size();
priority_queue<int> queue;
int pos = (size + 1) / 2;
for (int i = 0; i < size; i++) {
if (queue.size() == pos) {
if (queue.top() > nums[i]) {
queue.pop();
queue.push(nums[i]);
}
}
else {
queue.push(nums[i]);
}
}
return queue.top();
}
源码实现: github源码地址