内容包括:
C++语言描述。
// 快速排序
void quickSort(int a[], int left, int right)
{
if(left < right)
{
int i = left, j = right;
int x = a[left];
while(i < j)
{
while(i < j && a[j] >= x)
--j;
if(i < j) a[i++] = a[j];
while(i < j && a[i] < x)
++i;
if(i < j) a[j--] = a[i];
}
a[i] = x;
quickSort(a, left, i - 1);
quickSort(a, i + 1, right);
}
}
/* LintCode-761: 数组和的最小子集
* 问题:非负整数数组. 取数组中的一部分元素, 使得它们的和大于数组中其余元素的和,
* 求出满足条件的元素数量最小值。
* 给出 nums = [3, 1, 7, 1], 返回 1
* 给出 nums = [2, 1, 2], 返回 2
*/
int minElement(vector<int>& arr){
sort(arr.begin(), arr.end());
int sum = 0;
for (int i = 0; i < arr.size(); i++)
{
sum += arr[i];
}
sum = sum/2 + 1;
int cnt = 0;
for (int i = arr.size()-1; i >= 0 ; --i)
{
sum -= arr[i];
++cnt;
if(sum <= 0) return cnt;
}
}
/*
* 求最短子数组的大小,要求子数组的和>=s。
* Minimum Size Subarray sum
* For example, given the array [2,3,1,2,4,3,2,2] and s = 7, Output: 2,
* the subarray [4,3] has the minimal length, [3,2,2] dose Not.
*/
int minSumSize(vector<int>& nums, int s)
{
// sum是滑动窗口的和,start是窗口的起始位置
int ret = INT_MAX, sum = 0, start = 0;
for(int i = 0; i < nums.size(); ++i)
{
sum += nums[i];
while(start <= i && sum >=s)
{
// 记录最短长度
ret = min(ret, i - start + 1);
// 窗口右移
sum -= nums[start++];
}
}
return ret == INT_MAX ? -1 : ret;
}
/* LeeCode-168 Majority Element
* 给定一个大小为n的数组,找出主元素。主元素就是出现次数大于floor(n/2)次的元素。
* 你可以假设数组是非空的,并且主元素始终存在于数组中。
* Input: [2,2,1,1,1,2,2] 返回:2
*/
int majorityElement(vector<int>& arr) {
int ret = 0, cnt = 0;
for (int num : arr) {
if (0 == cnt) { //记录当前num
ret = num;
++cnt;
} else if( num == ret) { //遇到同一个数
++cnt;
} else {
--cnt;
}
}
return ret;
}
//进阶问题,出现次数大于floor(n/3)的所有元素。
// Input: [1,1,1,3,3,2,2,2] Output: [1,2]
// 摩尔投票法 Moore Voting
vector<int> majorElement(vector<int>& nums)
{
vector<int> ret;
int a = 0, b = 0, cnt1 = 0, cnt2 = 0;
for(int num : nums) {
if(num == a) {
++cnt1;
} else if(num == b) {
++cnt2;
} else if(cnt1 == 0) {
a = num; cnt1 = 1;
} else if(cnt2 == 0) {
b = num; cnt2 = 1;
} else {
--cnt1; --cnt2;
}
}
cnt1 = cnt2 = 0;
for (int num : nums) {
if(num == a) ++cnt1;
else if(num == b) ++cnt2;
}
if(cnt1 > nums.size()/3) ret.push_back(a);
if(cnt2 > nums.size()/3) ret.push_back(b);
return ret;
}
/*
* 连续子数组的最大和,返回和。
* Input: [-2,1,-3,4,-1,2,1,-5,4] Output: 6
* 最大和的子数组是[4,-1,2,1]
*/
int maxSubSum(vector<int>& nums)
{
int retSum = INT_MIN, curSum = 0;
for(int i = 0; i < nums.size(); ++i) {
if(curSum <= 0) {
curSum = nums[i];
} else {
curSum += nums[i];
}
if(curSum > retSum) {
retSum = curSum;
}
}
return retSum;
}
/*
* 求无序数组的中位数,复杂度要求<=O(N*logN)
*/
int partSort(int a[], int start, int end)
{
int left = start;
int right = end;
int key = a[end];
while(left < right)
{
while(a[left] <= key && left < right) ++left;
while(a[right] >= key && left < right) --right;
if(left < right)
swap(a[left], a[right]);
}
swap(a[right], a[end]);
return left;
}
int getMedian(int a[], int len)
{
int start = 0;
int end = len - 1;
// 不论len是奇偶数,mid都用 len/2 ;
int mid = len / 2; //注意不是 (len-1)/2
int part = partSort(a, start, end);
while(part != mid)
{
if(part > mid)
part = partSort(a, start, part - 1);
else
part = partSort(a, part + 1, end);
}
return a[mid];//注意不是mid+1
}
/*
* 求两个有序数组的中位数,复杂度要求O(log(m+n))。
* nums1 = [1, 2], nums2 = [3, 4]; The median is (2 + 3)/2 = 2.5
* nums1 = [1, 3], nums2 = [2]; The median is 2.0
*/
// k in {(m+n+1)/2, (m+n+2)/2}
int findKth(vector<int>& nums1, int i, vector<int>& nums2, int j, int k)
{
if(i > nums1.size()) {
//在nums2中找到从j开始的第k个数
return nums2[j+k-1];
}
if(j > nums2.size()) {
return nums1[i+k-1];
}
if(1 == k) {
return min(nums1[i], num2[j]);
}
// 若剩余大小不足k/2,则从另一个数组中取第k/2个数
int mid_a = (i + k/2 -1 < nums1.size()) ? nums1[i + k/2 -1] : INT_MAX;
int mid_b = (j + k/2 -1 < nums2.size()) ? nums2[j + k/2 -1] : INT_MAX;
if(mid_a < mid_b)
{
return findKth(nums1, i + k/2, num2, j, k - k/2);
} else {
return findKth(nums1, i, num2, j + k/2, k - k/2);
}
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size(), n = nums2.size(), left = (m + n + 1) / 2, right = (m + n + 2) / 2;
return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;
}
/*
[解释如下:](https://www.cnblogs.com/grandyang/p/4465932.html)
假设两个有序数组的长度分别为m和n,由于两个数组长度之和 m+n 的奇偶不确定,因此需要分情况来讨论,对于奇数的情况,直接找到最中间的数即可,偶数的话需要求最中间两个数的平均值。使用一个小trick:
分别找第 (m+n+1) / 2 个,和 (m+n+2) / 2 个,然后求其平均值即可,这对奇偶数均适用。若 m+n 为偶数的话,取这两个数的平均值;若 m+n 为奇数的话,那么其实 (m+n+1) / 2 和 (m+n+2) / 2 的值相等,相当于两个相同的数字相加再除以2,还是其本身。
这里需要定义一个函数来在两个有序数组中找到第K个元素。K 就是(m+n+1) / 2 或者(m+n+2) / 2。
使用两个变量i和j分别来标记数组 nums1 和 nums2 的起始位置。先考虑边界情况:
1,当某一个数组的起始位置大于等于其数组长度时,说明其所有数组均已经查找过了,只需要直接在另一个数组中找从i或j开始的第k个数就可以了。
2,当K=1的时候,变成分别查找第1个数,只要比较 nums1 和 nums2 的起始位置i和j上的数字,然后直接返回。
难点就在于一般的情况怎么处理,因为需要在两个有序数组中找到第K个元素。
为了加快搜索的速度,可以使用二分法,分别在 nums1 和 nums2 中查找第 K/2 个元素。
先 check 一下,数组中到底存不存在第 K/2 个数字,如果存在就取出来,否则就赋值上一个整型最大值,因为目的是要在 nums1 或者 nums2 中先淘汰 K/2 个较小的数字,判断的依据就是看 midVal1 和 midVal2 谁更小,但如果某个数组的个数都不到 K/2 个,就将其对应的 midVal 值设为整型最大值,表示不从这个数组淘汰出去。
*/
//---------------------------------
/*
* 寻找数组的平衡点问题
* 平衡点:比如int numbers[]={1,3,5,7,8,25,4,20};
* 25前面的总和为24,25后面的总和也是24,25这个点就是平衡点。
* O(2n)算法如下:
*/
int findBalance(int arr[], int len)
{
long sumLeft = 0;
long sumRight = 0;
for(int i=1; i < len; ++i)
{
sumRight += arr[i];
}
for(int j = 1; j < len; ++j)
{
sumLeft += arr[j-1];
sumRight -= arr[j];
if(sumLeft == sumRight)
return j;
}
return -1;
}
/*
* 在数组里查找这样的数,其左边的数都小于等于它,右边的数都大于等于它。
* 使用额外数组,比如rightMin[],来帮我们记录原始数组array[i]右边(包括自己)的最小值。
* 假如原始数组为: array[] = {7, 10, 2, 6, 19, 22, 32}, 那么rightMin[] = {2, 2, 2, 6, 19, 22, 32}.
* 从头开始遍历原始数组时,我们保存一个当前最大值 max, 如果当前最大值刚好等于rightMin[i],
* 那么这个最大值即为所求。
* 例如数组 {7, 10, 2, 6, 19, 22, 32} 返回19;
* 数组 {1,3,5,7,8,25,4,20},返回第二个数3.
*/
int smallLarge(int data[], int len)
{
if(data == NULL || len < 1) return -1;
std::vector<int> rightMin(len);
rightMin[len-1] = data[len-1];
for(int i = len - 2; i >= 0; --i)
{
rightMin[i] = min(data[i], rightMin[i+1]);
}
int leftMax = data[0];
for(int i = 1; i < len; ++i)
{
// [0, i]的最小值
leftMax = max(data[i], leftMax);
if(leftMax == rightMin[i])
{
return data[i];
}
}
return -1;
}
// 求两个数组的对称差集,即只在其中一个数组中出现过的数字组成的集合。
// C++ STL库函数:std::set_symmetric_difference()
// 例如 {1, 3, 5, 7, 9, 11} 和 {1, 1, 2, 3, 5, 8, 13}
// 它们的差集是:{2, 7, 8, 9, 11, 13}
// 两个无序数组的差集:互相二分查找,复杂度为 m*log(n) + n*log(m)。
vector<int> vec_diff_1(vector<int>& vm, vector<int>& vn)
{
vector<int> vec_ret;
for(int i = 0; i < vm.size(); i++)
{
if(0 == std::binary_search(vn.begin(), vn.begin()+vn.size(), vm[i]))
{
vec_ret.push_back(vm[i]);
}
}
for(int i = 0; i < vn.size(); i++)
{
if(0 == std::binary_search(vm.begin(), vm.begin()+vm.size(), vn[i]))
{
vec_ret.push_back(vn[i]);
}
}
// 对结果排序,可以省略
sort(vec_ret.begin(), vec_ret.end());
return vec_ret;
}
// 两个有序数组的差集:复杂度O(m+n)
// 事先排序两个数组复杂度:mlog(m)+nlog(n)
vector<int> vec_diff_2(vector<int>& vm, vector<int>& vn)
{
vector<int> result;
int first_m=0, first_n=0;
int last_m = vm.size();
int last_n = vn.size();
while(first_m != last_m && first_n != last_n)
{
if(vm[first_m] < vn[first_n])
{
result.push_back(vm[first_m]);
++first_m;
}
else if(vn[first_n] < vm[first_m])
{
result.push_back(vn[first_n]);
++first_n;
}
else {
++first_m;
++first_n;
}
}
copy(vm.begin()+first_m, vm.end(), std::inserter(result, result.begin()+result.size()));
copy(vn.begin()+first_n, vn.end(), std::inserter(result, result.begin()+result.size()));
return result;
}
// 求两个数组的交集
// 例如 {1, 3, 5, 7, 9, 11} 和 {1, 1, 2, 3, 5, 8, 13}
// 它们的交集是:{1,3,5}
vector<int> vec_intersection(vector<int>& vm, vector<int>& vn)
{
vector<int> result;
int first_m=0, first_n=0;
int last_m = vm.size();
int last_n = vn.size();
while(first_m != last_m && first_n != last_n)
{
if(vm[first_m] < vn[first_n])
{
++first_m;
}
else if(vn[first_n] < vm[first_m])
{
++first_n;
}
else { // vm[first_m] == vn[first_n]
result.push_back(vm[first_m]);
++first_m;
++first_n;
}
}
return result;
}
/*
* 最长上升子序列
* 例如[10,9,2,5,3,7,20,18] 返回4,[2,3,7,20]或者[2,3,7,18]
*/
int maxIncSeq(vector<int>& nums)
{
vector<int> vbuf;
for(int i = 0; i < nums.size(); ++i)
{
//找到第一个>=当前值的位置
vector<int>::iterator it = lower_bound(vbuf.begin(), vbuf.end(), nums[i]);
if(it == vbuf.end())
vbuf.push_back(nums[i]);
else
*it = nums[i];
}
return vbuf.size();
}
// 下面这种写法也行:
int maxIncSub(int arr[], int n)
{
int len = 0;
int* buf = new int[n+1];
for(int i = 0; i < n; i++)
{
// 二分查找第一个>=当前值的位置
int pos = lower_bound(buf, buf+len, arr[i]) - buf;
if(pos == len) {
buf[len++] = arr[i];
}
else {
buf[pos] = arr[i];
}
}
delete[] buf;
return len;
}
//三种颜色排序问题
void sort_colors(int[] colors, int len)
{
int left = 0, right = len - 1;
int cur = 0;
while(cur <= right)
{
if(colors[cur] == 0)
{
swap(colors[cur],colors[left]);
left++;
cur++;
}
else if(colors[cur] == 2)
{
swap(colors[cur], colors[right]);
right--;
}
else // if(colors[cur] == 1)
{
cur++;
}
}
}
未完待续。