leetcode-C++笔记

leetcode-C++笔记

1.小技巧

1.判断两个浮点数a,b是否相等时abs(a-b)是否小于
一个阈值,例如1e-9.

2.用char的值作为数组下标,需要考虑可能出现负数,
需要强转unsigned char 

3.善用C++中的STL,详见《算法笔记》

1.给定一个有序数组,去除重复值保证独一无二,不使用额外空间,返回最终数组的长度值。

Given a sorted array, remove the duplicates in place such that each element appear only once
and return the new length.
Do not allocate extra space for another array, you must do this in place with constant memory.
For example, Given input array A = [1,1,2],
Your function should return length = 2, and A is now [1,2].

给定一个有序数组,去除重复值保证独一无二,
不使用额外空间,返回最终数组的长度值。

解法:

使用两个下标值,一个index,一个i
i是用来遍历array的,
如果array为空,直接return 0;
其他
index和i都从0开始
因为给定的是有序array
所以如果index下标处的值和i下标处的值不相等
那么++index,并将i下标处的值拷贝到新的index下标处
	如果相等,那么新数组不需要存储i下标处的值
	所以只有i++,index不变。
	index代表了新数组的最后一个下标,
	所以新数组的最终长度=index+1;
所以最终return index+1。

算法是这样,可以只记一个超短的答案

class Solution {
public:
int removeDuplicates(vector<int>& nums) {
return distance(nums.begin(), unique(nums.begin(), nums.end()));
}
};	

2.根据上一题改编,如果要求重复出现次数最多两次呢?

Follow up for ”Remove Duplicates”: What if duplicates are allowed at most twice?
For example, Given sorted array A = [1,1,1,2,2,3],
Your function should return length = 5, and A is now [1,1,2,2,3]

根据上一题改编,如果要求重复出现次数最多两次呢?

分析:加一个变量记录一下元素出现的次数,
因为是已经排序的数组,所以一个变量即可
如果是没有排序的数组,需要引用一个hashmap来记录出现的次数。

解法

因为每个数都有和前面的数相同的可能,最特殊的就是每个数
都与数组中其他的数都不同,这时候就需要遍历解决。
所以,应该有一个递增为1的for循环。
另外,不管数组里面的数相等与否,当数组的总长度<=2的,
处理的结果还是原数组,所以可以直接返回原数组的大小。

本题的前提还是基于sorted 数组,所以还是在纸上模拟操作好理解。
然后就是核心思想:
最多保存两次,那么当前值要不要保存,与前一个值有关吗?
答案是不确定的:
	1.当前一个值和对当前值不等时,当然保存!
	2.当前一个值和当前值相等时,不确定!因为最多可以保存两个相,不确定现在是几个了

这里的算法充分利用了sorted这一条件:
将当前值与已保存数组的前2个值进行比较:
	1.前2个值与当前值不等时,
		那么现在不论保存的前1个值是否与当前值相等,
		根据最多可以重复保存两次的原则,
		当前值都应该进行保存;
	2.前2个值与当前值相等时:
		根据sorted原则,也就是说明前2个值和前1个值都与当前值相等
		同样根据最多重复保存两次相等的原则,
		当前值绝对不能进行保存,否则就=3,>2了。
	同样的,3次呢?还是根据这样扩展,代码中相应的地方改成3就可以了。

推荐使用略长一点,但是扩展性好一些的代码,例如将occur<3,
就编程了允许重复最多3次。

// LeetCode, Remove Duplicates from Sorted Array II
// ????? O(n)?????? O(1)
// @author hex108 (https://github.com/hex108)
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if (nums.size() <= 2) return nums.size();
int index = 2;
for (int i = 2; i < nums.size(); i++){
if (nums[i] != nums[index - 2])
nums[index++] = nums[i];
}
return index;
}
};

3.给定了一个sorted数组,给定一个值进行查找 但是注意,这里还对sorted数组进行了旋转,且假设了 这个数组中值互不相等

Search in Rotated Sorted Array

Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
You are given a target value to search. If found in the array return its index, otherwise return -1.
You may assume no duplicate exists in the array.

题目给定了一个sorted数组,给定一个值进行查找
但是注意,这里还对sorted数组进行了旋转,且假设了
这个数组中值互不相等
如果值存在就返回其下标,如果不存在,就返回-1

分析:
二分查找,难度主要在于左右边界的确定。

解法:
具体关系还是在纸上画一画就很显然了。
初始化first=0,last=nums.size();还有mid

1.如果要找的target正好等于对应的mid下标对应处的值,
也就是找到了,直接返回mid作为下标即可;
2.否则,如果first处的值<=mid处的值,说明什么呢?
别忘了,因为是sorted数组,所以说明从first到mid,
数组里的数是递增的。
就是根据这一点就更好定位了。
此时,如果target大于等于first处的值,并且小于mid处的值,
说明下一轮循环查找应该在first-mid这个范围找,
所以last=mid;
否则,也就是不在这一段,应该first=mid+1;

3.同样的,剩下的可能是first-mid这个区间并不是递增的。
	这个说明什么了呢?
	对立面,因为是将数组旋转了,所以,
	mid-(last-1)这个区间是递增的。用target比较这个区间
	最大最小值,也就是比较边界值mid处值和last-1处值。
	如果target大于mid处的值,并且小于等于last-1处的值
	那么说明下一轮查找应该在这个区间展开,
	也就是first=mid+1;
	否则,也就是应该在另一半区间进行查找:
	last=mid.



// LeetCode, Search in Rotated Sorted Array
// ????? O(log n)?????? O(1)
class Solution {
public:
int search(const vector<int>& nums, int target) {
int first = 0, last = nums.size();
while (first != last) {
const int mid = first + (last - first) / 2;
if (nums[mid] == target)
return mid;
if (nums[first] <= nums[mid]) {
if (nums[first] <= target && target < nums[mid])
last = mid;
else
first = mid + 1;
} else {
if (nums[mid] < target && target <= nums[last-1])
first = mid + 1;
else
last = mid;
}
}
return -1;
}
};

4.如果sorted旋转数组中的数字是重复元素呢?那应该怎么解决

Search in Rotated Sorted Array II
??
Follow up for ”Search in Rotated Sorted Array”: What if duplicates are allowed?
Would this affect the run-time complexity? How and why?
Write a function to determine if a given target is in the array.

如果sorted旋转数组中的数字是重复元素呢?那应该怎么解决。

分析:

允许重复元素,则上一题中如果mid处的值>=first处的值,
那么,first-mid为递增序列的假设就不能成立,
如1,3,1,1,1
如果mid处的值>=first处的值不能确定递增,那就把它拆成两个条件:
	1.如果mid处的值>first处的值,则first-mid区间一定递增;
	2.如果mid处的值=first处的值,first++,往下看一步。

总结一下与上一题的解法变化:
就是单独将first处的值和mid处的值相等时列出:
并设置first++,即可。

	// LeetCode, Search in Rotated Sorted Array II
	// ????? O(n)?????? O(1)
	class Solution {
	public:
	bool search(const vector<int>& nums, int target) {
	int first = 0, last = nums.size();
	while (first != last) {
	const int mid = first + (last - first) / 2;
	if (nums[mid] == target)
	return true;
	if (nums[first] < nums[mid]) {
	if (nums[first] <= target && target < nums[mid])
	last = mid;
	else
	first = mid + 1;
	} else if (nums[first] > nums[mid]) {
	if (nums[mid] < target && target <= nums[last-1])
	first = mid + 1;
	else
	last = mid;
	} else
	//skip duplicate one
	first++;
	}
	return false;
	}
	};

5.Median of Two Sorted Arrays

Median of Two Sorted Arrays
??
There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted
arrays. The overall run time complexity should be O(log(m + n))

分析:

这是一个非常经典的题。
这道题更为通用的形式是:给定两个已经排好序的数组,
找到两者所有元素中第k大的元素。
Om+n的解法比较直观,直接merge两个数组,然后求第k大的元素。
不过我们仅仅需要第k大的元素,是不需要“排序”这么昂贵的操作的。
可以用一个计数器,记录但施工前已经找到第m大的元素了。
同时我们使用两个指针pa和pb,分别指向a数组和b数组的第一个元素。
使用类似于merge sort的原理,
如果数组a当前元素小,那么pa++,同时m++;
如果数组b当前元素小,那么pb++,同时m++;
最终当m==k的时候,就得到了我们的答案,Ok时间,O1空间。
但是,当k很接近m+n的时候,这个方法还是Om+n的。

更好的方案?
我们可以考虑从k入手。
如果我们每次都能够删除一个一定在第k大元素之前的元素,
那么我们需要进行k次。
但是如果每次我们都删除一半呢?
由于a和b都是有序的,我们可以使用二分查找,
也是充分利用了“有序”。

假设a和b的元素个数都大于k/2,我们将a的第k/2个元素,
即a[k/2-1]和b的第k/2个元素,即b[k/2-1]进行比较,
有以下三种情况,为了简化,这里先假设k为偶数,所得到的结论对于
k为奇数也是同样成立。
	1.a[k/2-1] == b[k/2-1]
	2.a[k/2-1] > b[k/2-1]
	3.a[k/2-1] < b[k/2-1]

如果a[k/2-1] < b[k/2-1],意味着a[0]到a[k/2-1]的肯定在topk元素的范围内
也就是说,a[k/2-1]不可能大于第k大元素。
因此,我们可以放心的删除a数组的这k/2个元素。
同理,b也是。
而当a[k/2-1] == b[k/2-1]时,说明找到了第k大的元素,
直接返回其中任意一个即可。

可以写一个递归函数,那么函数什么时候应该终止呢?
	1.当a或b为空时,直接返回b[k-1]或a[k-1];
	2.当k=1时,返回min(a[0],b[0]);
	3.当a[k/2-1] == b[k/2-1]时,返回其中任意一个。

	// LeetCode, Median of Two Sorted Arrays
	// ????? O(log(m+n))?????? O(log(m+n))
	class Solution {
	public:
	double findMedianSortedArrays(const vector<int>& A, const vector<int>& B) {
	const int m = A.size();
	const int n = B.size();
	int total = m + n;
	if (total & 0x1)
	return find_kth(A.begin(), m, B.begin(), n, total / 2 + 1);
	else
	return (find_kth(A.begin(), m, B.begin(), n, total / 2)
	+ find_kth(A.begin(), m, B.begin(), n, total / 2 + 1)) / 2.0;
	}
	private:
	static int find_kth(std::vector<int>::const_iterator A, int m,
	std::vector<int>::const_iterator B, int n, int k) {
	//always assume that m is equal or smaller than n
	if (m > n) return find_kth(B, n, A, m, k);
	if (m == 0) return *(B + k - 1);
	if (k == 1) return min(*A, *B);
	//divide k into two parts
	int ia = min(k / 2, m), ib = k - ia;
	if (*(A + ia - 1) < *(B + ib - 1))
	return find_kth(A + ia, m - ia, B, n, k - ia);
	else if (*(A + ia - 1) > *(B + ib - 1))
	return find_kth(A, m, B + ib, n - ib, k - ib);
	else
	return A[ia - 1];
	}
	};

6.给定一个无序整数数组,计算出该数组最长连续数序列的长度

Longest Consecutive Sequence
??
Given an unsorted array of integers, find the length of the longest consecutive elements sequence.
For example, Given [100, 4, 200, 1, 3, 2], The longest consecutive elements sequence is [1,
2, 3, 4]. Return its length: 4.
Your algorithm should run in O(n) complexity.

题目:给定一个无序整数数组,
计算出该数组最长连续数序列的长度。

分析:

如果允许Onlogn的复杂度,那么可以先排序,但是本题要求On
由于序列里面的元素是无序的,有要求On,首先想到用哈希表。
用一个哈希表unordered_map<int,bool> used 记录每个元素是否
使用,对每个元素,以该元素为中心,往左右扩张,直到不连续位置,记录下
最长的长度。

解法:

先将给定的数的bool都统一设定为false;
如果一个值的bool为true,
1.说明我们之前已经遍历过他,并且将其修改为true;
我们遍历初始找的一定是false值开始的。
unordered_map<int,bool>默认bool值同样是false
找到一个length自然为1;
然后就是让其向左向右分别遍历,如果隔壁的bool也是false,
那么这个值可能没遍历访问过,也可能根本就没有往里面存储过。
但是我们在for循环中有map.find()!=map.end()
如果我们根本就没有往里面存储过,那么这条语句就会起到过滤作用。
1.过滤边界问题;
2.过滤掉根本没有存储过的false情况。
之后括号里面符合的只有我们往里面存储过,但是没有访问遍历过的情况。
这样之后再设置为true就没有问题了。情形比较简单,不用在纸上画图也可以理解。

// Leet Code, Longest Consecutive Sequence
// ????? O(n)?????? O(n)
class Solution {
public:
int longestConsecutive(const vector<int> &nums) {
unordered_map<int, bool> used;
for (auto i : nums) used[i] = false;
int longest = 0;
for (auto i : nums) {
if (used[i]) continue;
int length = 1;
used[i] = true;
for (int j = i + 1; used.find(j) != used.end(); ++j) {
used[j] = true;
++length;
}
for (int j = i - 1; used.find(j) != used.end(); --j) {
used[j] = true;
++length;
}
longest = max(longest, length);
}
return longest;
}
};

7.给定一个整数数组,给定一个目标数, 找2个数组里面的数和=目标数。 并且返回这两个数的下标值,要求两个数下标值不同。 并且假设输入数据只有唯一解。

Two Sum
??
Given an array of integers, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where
index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not
zero-based.
2.1 ?? 11
You may assume that each input would have exactly one solution.
Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2

题目:

给定一个整数数组,给定一个目标数,
找2个数组里面的数和=目标数。
并且返回这两个数的下标值,要求两个数下标值不同。
并且假设输入数据只有唯一解。

分析:

1.暴力On^2;
2.hash,用一个hash表,存储每个数对应的下标,On
3.先排序,然后左右夹逼,排序NlogN,左右夹逼ON,
但是注意这题需要返回下标,而不是数字本身,因此这个方法不行。

有一个注意点,就是题目还要求下标值不是从0开始。

8.给定一个整数数组, 求所有的3元祖,3个数的和为0

3Sum
??
Given an array S of n integers, are there elements a,b,c in S such that a + b + c = 0? Find all unique
triplets i

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值