昨天看了24道,今天再接再厉。
一. 排序篇(6)
LeetCode215: 数组中的第K个最大元素
- 思路1:快排
- 思路2:堆排序
class Solution { public: void maxHeapify(vector<int>& a, int i, int heapSize) { int l = i * 2 + 1, r = i * 2 + 2, largest = i; if (l < heapSize && a[l] > a[largest]) { largest = l; } if (r < heapSize && a[r] > a[largest]) { largest = r; } if (largest != i) { swap(a[i], a[largest]); maxHeapify(a, largest, heapSize); } } void buildMaxHeap(vector<int>& a, int heapSize) { for (int i = heapSize / 2; i >= 0; --i) { maxHeapify(a, i, heapSize); } } int findKthLargest(vector<int>& nums, int k) { int heapSize = nums.size(); buildMaxHeap(nums, heapSize); for (int i = nums.size() - 1; i >= nums.size() - k + 1; --i) { swap(nums[0], nums[i]); --heapSize; maxHeapify(nums, 0, heapSize); } return nums[0]; } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/kth-largest-element-in-an-array/solutions/307351/shu-zu-zhong-de-di-kge-zui-da-yuan-su-by-leetcode-/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode179: 最大数
- 技巧:创建一个stringstream 对象,并通过运算符 ”<<“ 将数据传递给 stringstream 对象。
class Solution { public: string largestNumber(vector<int>& nums) { vector<string> str; for(auto i : nums) { str.push_back(to_string(i)); } // 使用 lambda 比较 elements. auto cmp = [](string left, string right) { return left + right > right + left; }; sort(str.begin(),str.end(), cmp); stringstream ss; for(auto c : str) { ss << c; } string ans = ss.str(); if(ans[0] == '0'){ return "0"; } return ans; } }; 作者:宫水三叶 链接:https://leetcode.cn/problems/largest-number/solutions/716725/gong-shui-san-xie-noxiang-xin-ke-xue-xi-vn86e/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
面试题17.14: 最小的K个数
- 思路1:直接sort
- 思路2:堆排序
class Solution { public: vector<int> smallestK(vector<int>& arr, int k) { vector<int> vec(k, 0); if (k == 0) { // 排除 0 的情况 return vec; } priority_queue<int> Q; for (int i = 0; i < k; ++i) { Q.push(arr[i]); } for (int i = k; i < (int)arr.size(); ++i) { if (Q.top() > arr[i]) { Q.pop(); Q.push(arr[i]); } } for (int i = 0; i < k; ++i) { vec[i] = Q.top(); Q.pop(); } return vec; } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/smallest-k-lcci/solutions/590916/zui-xiao-kge-shu-by-leetcode-solution-o5eg/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
堆排序手撕
二叉树与树组的对应。
void adjust(int arr[], int len, int index)
{
int left = 2*index + 1;
int right = 2*index + 2;
int maxIdx = index;
if(left<len && arr[left] > arr[maxIdx]) maxIdx = left;
if(right<len && arr[right] > arr[maxIdx]) maxIdx = right; // maxIdx是3个数中最大数的下标
if(maxIdx != index) // 如果maxIdx的值有更新
{
swap(arr[maxIdx], arr[index]);
adjust(arr, len, maxIdx); // 递归调整其他不满足堆性质的部分
}
}
void heapSort(int arr[], int size)
{
for(int i=size/2 - 1; i >= 0; i--) // 对每一个非叶结点进行堆调整(从最后一个非叶结点开始)
{
adjust(arr, size, i);
}
for(int i = size - 1; i >= 1; i--)
{
swap(arr[0], arr[i]); // 将当前最大的放置到数组末尾
adjust(arr, i, 0); // 将未完成排序的部分继续进行堆排序
}
}
————————————————
版权声明:本文为CSDN博主「大白技术控」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lzuacm/article/details/52853194
快排手撕
分而治之(递归)。
在数组的头部和尾部分别设置一个哨兵
,同时向对方走去。尾部的哨兵如发现有比基准数小的数,停下。头部的哨兵如发现有比基准数大的数,停下。交换两个数。再重新走重复前面的交换过程。直到两个哨兵相遇,交换基准数和尾哨兵。
void quickSort(int s[], int l, int r)
{
if (l< r)
{
int i = l, j = r, x = s[l];
while (i < j)
{
while(i < j && s[j]>= x) // 从右向左找第一个小于x的数
j--;
if(i < j)
s[i++] = s[j];
while(i < j && s[i]< x) // 从左向右找第一个大于等于x的数
i++;
if(i < j)
s[j--] = s[i];
}
s[i] = x;
quickSort(s, l, i - 1); // 递归调用
quickSort(s, i + 1, r);
}
}
归并手撕
分而治之(递归)。
void mergeArr(int arr[], int low, int mid, int hight) {
int* tempArr = new int[hight - low + 1];
int i = low, j = mid + 1, k = 0;
while (i <= mid && j <= hight) {
if (arr[i] < arr[j]) {
tempArr[k] = arr[i];
i++;
}
else {
tempArr[k] = arr[j];
j++;
}
k++;
}
// 如果 arr[low] 到 arr[mid] 区间中的数组还没有比较完成 ,直接复制到tempArr 中
while (i <= mid) {
tempArr[k] = arr[i];
i++;
k++;
}
// 如果 arr[mid+1] 到 arr[hight] 区间中的数组还没有比较完成 ,直接复制到tempArr 中
while (j <= hight) {
tempArr[k] = arr[j];
j++;
k++;
}
// 比较完成之后 将原本的数组arr 下标 low-hight 对应的内容 进行改变
i = low;
for (int tempK = 0;((tempK < k)&&(i<=hight));tempK++) {
arr[i] = tempArr[tempK];
i++;
}
delete[] tempArr;
tempArr = NULL;
}
/**
*功能:拆分有序的序列两两排序-拆解结束的条件 子序列长度为1的时候
*/
void sortArr(int arr[], int low, int hight) {
if (low < hight) {
int mid = (hight + low) / 2;
sortArr(arr,low,mid);// 递归拆解左边的序列
sortArr(arr, mid + 1, hight);// 递归拆解左边的序列
mergeArr(arr, low, mid, hight);// 将两个有序的子序列(arr[low至mid]、arr[mid+1至hight] 排序合并成一个新的有序列
}
}
————————————————
版权声明:本文为CSDN博主「allAboutLaoWang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/allAboutLaoWang/article/details/109647408
归并排序算法详解(c++ 版 递归实现)_归并排序c++代码_allAboutLaoWang的博客-CSDN博客
二.二分查找篇(6)
LeetCode34: 在排序数组中查找元素的第一个和最后一个位置
- 思路:寻找数组中「第一个等于 target的位置」和「第一个大于 target的位置减一」
class Solution { public: int binarySearch(vector<int>& nums, int target, bool lower) { int left = 0, right = (int)nums.size() - 1, ans = (int)nums.size(); while (left <= right) { int mid = (left + right) / 2; if (nums[mid] > target || (lower && nums[mid] >= target)) { right = mid - 1; ans = mid; } else { left = mid + 1; } } return ans; } vector<int> searchRange(vector<int>& nums, int target) { int leftIdx = binarySearch(nums, target, true); int rightIdx = binarySearch(nums, target, false) - 1; if (leftIdx <= rightIdx && rightIdx < nums.size() && nums[leftIdx] == target && nums[rightIdx] == target) { return vector<int>{leftIdx, rightIdx}; } return vector<int>{-1, -1}; } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/solutions/504484/zai-pai-xu-shu-zu-zhong-cha-zhao-yuan-su-de-di-3-4/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode69: x的平方根
- 思路:二分查找
class Solution { public: int mySqrt(int x) { int l = 0, r = x, ans = -1; while (l <= r) { int mid = l + (r - l) / 2; if ((long long)mid * mid <= x) { ans = mid; l = mid + 1; } else { r = mid - 1; } } return ans; } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/sqrtx/solutions/238553/x-de-ping-fang-gen-by-leetcode-solution/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode74: 搜索二维矩阵
- 思路:将矩阵每一行拼接在上一行的末尾,会得到一个升序数组,我们可以在该数组上二分找到目标元素。代码实现时,可以二分升序数组的下标,将其映射到原矩阵的行和列上。
class Solution { public: bool searchMatrix(vector<vector<int>>& matrix, int target) { int m = matrix.size(), n = matrix[0].size(); int low = 0, high = m * n - 1; while (low <= high) { int mid = (high - low) / 2 + low; int x = matrix[mid / n][mid % n]; if (x < target) { low = mid + 1; } else if (x > target) { high = mid - 1; } else { return true; } } return false; } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/search-a-2d-matrix/solutions/688117/sou-suo-er-wei-ju-zhen-by-leetcode-solut-vxui/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode240: 搜索二维矩阵II
- 思路1:对每一行进行二分查找。
class Solution { public: bool searchMatrix(vector<vector<int>>& matrix, int target) { for (const auto& row: matrix) { auto it = lower_bound(row.begin(), row.end(), target); if (it != row.end() && *it == target) { return true; } } return false; } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/search-a-2d-matrix-ii/solutions/1062538/sou-suo-er-wei-ju-zhen-ii-by-leetcode-so-9hcx/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
思路2:从右上角开始遍历,向左数字会变小,向下数字会变大。
public boolean searchMatrix(int[][] matrix, int target) { if (matrix.length == 0 || matrix[0].length == 0) { return false; } int row = 0; int col = matrix[0].length - 1; while (row < matrix.length && col >= 0) { if (target > matrix[row][col]) { row++; } else if (target < matrix[row][col]) { col--; } else { return true; } } return false; } 作者:windliang 链接:https://leetcode.cn/problems/search-a-2d-matrix-ii/solutions/118335/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-5-4/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode33: 搜索旋转排序数组
- 思路:判断数组的有序部分。
class Solution { public: int search(vector<int>& nums, int target) { int n = (int)nums.size(); if (!n) { return -1; } if (n == 1) { return nums[0] == target ? 0 : -1; } int l = 0, r = n - 1; while (l <= r) { int mid = (l + r) / 2; if (nums[mid] == target) return mid; if (nums[0] <= nums[mid]) { if (nums[0] <= target && target < nums[mid]) { r = mid - 1; } else { l = mid + 1; } } else { if (nums[mid] < target && target <= nums[n - 1]) { l = mid + 1; } else { r = mid - 1; } } } return -1; } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/search-in-rotated-sorted-array/solutions/220083/sou-suo-xuan-zhuan-pai-xu-shu-zu-by-leetcode-solut/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode153: 搜索旋转数组的最小值
- 思路:设置中点,与high比较。
class Solution { public: int findMin(vector<int>& nums) { int low = 0; int high = nums.size() - 1; while (low < high) { int pivot = low + (high - low) / 2; if (nums[pivot] < nums[high]) { high = pivot; } else { low = pivot + 1; } } return nums[low]; } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/solutions/698479/xun-zhao-xuan-zhuan-pai-xu-shu-zu-zhong-5irwp/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
三.数组和哈希表(18)
LeetCode283: 移动零
- 技巧:双指针
- 思路:右指针每回合都移动,左指针在右指针指向0时不移动。
class Solution { public: void moveZeroes(vector<int>& nums) { int n = nums.size(), left = 0, right = 0; while (right < n) { if (nums[right]) { swap(nums[left], nums[right]); left++; } right++; } } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/move-zeroes/solutions/489622/yi-dong-ling-by-leetcode-solution/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指offer21: 调整数组顺序使奇数位于偶数前面
- 技巧:双指针
- 技巧:x&1 位运算 等价于 x%2 取余运算,即皆可用于判断数字奇偶性。
LeetCode15: 三数之和
技巧:排序+双指针
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int len = nums.size();
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
for(int i=0; i<len; ++i){
if(nums[i] > 0)break;
int l=i+1, r=len-1;
while(l<r){
if(nums[l]+nums[r] == -nums[i]){
ans.push_back({nums[i], nums[l], nums[r]});
++l;--r;
while(l<r && nums[l]==nums[l-1])++l;
while(l<r && nums[r]==nums[r+1])--r;
}
else if(nums[l]+nums[r] > -nums[i]){
--r;
}
else{
++l;
}
}
while(i+1<len && nums[i+1]==nums[i])++i;
}
return ans;
}
};
LeetCode88:合并两个有序数组
思路1:类似合并有序链表,利用双指针。
思路2:逆向双指针,无需开辟新数组。
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int p1 = m - 1, p2 = n - 1;
int tail = m + n - 1;
int cur;
while (p1 >= 0 || p2 >= 0) {
if (p1 == -1) {
cur = nums2[p2--];
} else if (p2 == -1) {
cur = nums1[p1--];
} else if (nums1[p1] > nums2[p2]) {
cur = nums1[p1--];
} else {
cur = nums2[p2--];
}
nums1[tail--] = cur;
}
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/merge-sorted-array/solutions/666608/he-bing-liang-ge-you-xu-shu-zu-by-leetco-rrb0/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode4: 寻找两个正序数组的中位数 Hard Pass
LeetCode59: 螺旋矩阵II
- 技巧:模拟
class Solution { public: vector<vector<int>> generateMatrix(int n) { int num = 1; int left = 0, top = 0, right = n - 1, bottom = n - 1; //初始化数组 vector<vector<int>> res(n,vector<int>(n)); while (num <= n*n ) { //left to right for (int i = left; i <= right; ++i) res[top][i] = num++; ++top; //top to bottom for (int i = top; i <= bottom; ++i) res[i][right] = num++; --right; //right to left for (int i = right; i >= left; --i) res[bottom][i] = num++; --bottom; //bottom to top for (int i = bottom; i >= top; --i) res[i][left] = num++; ++left; } return res; } };
LeetCode498: 对角线遍历
思路如下:
- 每一趟对角线中元素的坐标(x, y)相加的和是递增的。
- 每一趟都是 x 或 y 其中一个从大到小(每次-1),另一个从小到大(每次+1)。
- 确定初始值。例如这一趟是 x 从大到小, x 尽量取最大,当初始值超过 x 的上限时,不足的部分加到 y 上面。
- 确定结束值。例如这一趟是 x 从大到小,这一趟结束的判断是, x 减到 0 或者 y 加到上限。
- 这一趟是 x 从大到小,那么下一趟是 y 从大到小,循环进行。 并且方向相反时,逻辑处理是一样的,除了x,y和他们各自的上限值是相反的。
vector<int> nums;
int m = matrix.size();
int n = matrix[0].size();
int i = 0; // i 是 x + y 的和
while (i < m + n)
{
// 第 1 3 5 ... 趟
int x1 = (i < m) ? i : m - 1; // 确定 x y 的初始值
int y1 = i - x1;
while (x1 >= 0 && y1 < n)
{
nums.push_back(matrix[x1][y1]);
x1--;
y1++;
}
i++;
if (i >= m + n) break;
// 第 2 4 6 ... 趟
int y2 = (i < n) ? i : n - 1; // 确定 x y 的初始值
int x2 = i - y2;
while (y2 >= 0 && x2 < m)
{
nums.push_back(matrix[x2][y2]);
x2++;
y2--;
}
i++;
}
return nums;
作者:Ikaruga
链接:https://leetcode.cn/problems/diagonal-traverse/solutions/11440/dui-jiao-xian-bian-li-fen-xi-ti-mu-zhao-zhun-gui-l/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指offer39: 数组中出现次数超过一半的数字
- 思路1:哈希表
class Solution { public: int majorityElement(vector<int>& nums) { unordered_map<int, int> counts; int majority = 0, cnt = 0; for (int num: nums) { ++counts[num]; if (counts[num] > cnt) { majority = num; cnt = counts[num]; } } return majority; } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/solutions/832356/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-pvh8/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 思路2:投票
class Solution { public: int majorityElement(vector<int>& nums) { int x = 0, votes = 0; for(int num : nums){ if(votes == 0) x = num; votes += num == x ? 1 : -1; } return x; } }; 作者:Krahets 链接:https://leetcode.cn/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/solutions/138691/mian-shi-ti-39-shu-zu-zhong-chu-xian-ci-shu-chao-3/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode31: 下一个排列
class Solution{
public:
void nextPermutation(vector <int> & nums){
int n = nums.size();
if(n <= 1) return;
int i = n - 2, j = n - 1, k = n - 1;
//find A[i] < A[j]
while(i >= 0 && nums[i] >= nums[j]){
--i, --j;
}
if(i >= 0){
//find A[i] < A[k]
while( nums[i] >= nums[k]) --k;
swap(nums[i], nums[k]);
}
reverse(nums.begin() + j, nums.end());
}
};
牛客Top200高频: 将字符串转化为整数 == 剑指offer 67: 把字符串转换成整数
用Rand7()实现Rand10()
详细解释参考如下链接
class Solution {
public:
int rand10() {
while(true) {
int num = (rand7() - 1) * 7 + rand7(); // 等概率生成[1,49]范围的随机数
if(num <= 40) return num % 10 + 1; // 拒绝采样,并返回[1,10]范围的随机数
}
}
};
LeetCode209:长度最小的子数组
- 技巧:滑动窗口
class Solution { public: int minSubArrayLen(int s, vector<int>& nums) { int n = nums.size(); if (n == 0) { return 0; } int ans = INT_MAX; int start = 0, end = 0; int sum = 0; while (end < n) { sum += nums[end]; while (sum >= s) { ans = min(ans, end - start + 1); sum -= nums[start]; start++; } end++; } return ans == INT_MAX ? 0 : ans; } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/minimum-size-subarray-sum/solutions/305704/chang-du-zui-xiao-de-zi-shu-zu-by-leetcode-solutio/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode1: 两数之和
- 技巧:哈希表
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int, int> hashtable; for (int i = 0; i < nums.size(); ++i) { auto it = hashtable.find(target - nums[i]); if (it != hashtable.end()) { return {it->second, i}; } hashtable[nums[i]] = i; } return {}; } }; 作者:力扣官方题解 链接:https://leetcode.cn/problems/two-sum/solutions/434597/liang-shu-zhi-he-by-leetcode-solution/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
LeetCode128: 最长连续序列
- 用哈希表存储每个端点值对应连续区间的长度
- 若数已在哈希表中:跳过不做处理
- 若是新数加入:
- 取出其左右相邻数已有的连续区间长度 left 和 right
- 计算当前数的区间长度为:cur_length = left + right + 1
- 根据 cur_length 更新最大长度 max_length 的值
- 更新区间两端点的长度值
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_map<int, int> mp;
int l, r, res = 0, len;
for(int num : nums) {
if(!mp[num]) {
l = mp[num - 1];
r = mp[num + 1];
len = l + r + 1;
if(res < len) res = len;
mp[num] = len;
mp[num - l] = len;
mp[num + r] = len;
}
}
return res;
}
};
LeetCode41: 缺失的第一个正数 Hard Pass
剑指offer03: 数组中重复的数字
- 思路:哈希表
LeetCode14: 最长公共前缀
- 思路:维护一个新的string变量。
class Solution { public: string longestCommonPrefix(vector<string>& strs) { std::string res = strs.empty() ? "" : strs[0]; if (strs.size() <= 1) { return res; } for (auto str1 : strs) { std::string str0 = res; res = ""; for (int i = 0; i < min(str1.size(), str0.size()); ++i) { if (str0[i] != str1[i]) { break; } res += str1[i]; } if (res.empty()) { return res; } } return res; } };
LeetCode162: 寻找峰值
- 思路:迭代爬坡以及其二分优化
class Solution { public: int findPeakElement(vector<int>& nums) { int l = 0, r = nums.size() - 1; while(l < r){ int m = (l+r) / 2; nums[m] < nums[m+1] ? l = m + 1 : r = m; } return l; } };
参考链接