Leetcode刷题总结(1)
(之前的没有总结,后面都记录一下,刷题上瘾哈!!!)
数组篇
- 最小操作次数使数组元素相等
今日收获:当问题复杂时可以考虑其对立事件
语法上:
*min_element(nums.begin(),nums.end());
可以求最小数,最大同理
C++11新特性:遍历数组:for(auto & num:nums)
注意引用与不引用的区别,引用遍历可以修改数组
- 非递减数列
is_sorted() 函数,此函数专门用于判断某个序列是否为有序序列。
可以尝试贪心算法;
考虑情况,定位到要改的数,改前还是改后。
- 杨辉三角
注意vector<vector< int >>v(numRows);二维数组,分配空间。
vectorv;与vectorv(n);区别:
1. vector< int >v,插入元素v.push_back(i); 声明一个容器v时,如果没有给他预定存储空间,则可以直接使用v.push_back(x)插入变量x,那么插入的第一个元素可以用v[0]访问到。
2.vector< int >v(n)插入元素是v[i]=x;使用 vector< int > v(n); 声明一个容器v时,如果给他预定存储空间则vector< int > v(n) 等价于vector v(n,0); 如果要使得位置0存储元素x,则只能使用v[0]=x,如果使用v.insert(x)插入变量x,那么v的第一个元素还是0,即v[0]=0,因为v.push_back(x)是将x插入到v[n],又因为声明v时,v最多能存储n个元素,即x根本没有成功插入容器v中。
v[i].resize(i+1);分配空间,i+1个元素,
贪心算法
- 用最少数量的箭引爆气球
c++11新特性 lamada表达式的使用以及二维数组排序
sort(points.begin(),points.end(),[](vector<int>&a,vector<int>&b){
return a[1]<b[1];
双指针
- 合并两个有序数组
这里我们使用了 ++ 和–的小技巧:a++ 和 ++a 都是将 a 加 1,但是 a++ 返回值为 a,而++a 返回值为 a+1。如果只是希望增加 a 的值,而不需要返回值,则推荐使用 ++a,其运行速度会略快一些。
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int pos=m-- + n-- - 1;
while(m >= 0 && n >=0){
nums1[pos--]=nums1[m]>nums2[n]?nums1[m--]:nums2[n--];
}
while(n>=0){
nums1[pos--]=nums2[n--];
}
}
};
其中int pos=m-- + n-- - 1;防止数组越界。等价于以下写法:
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int l=m-1;
int r=n-1;
int k=m +n -1;
while(m=l>=0&&r>=0)
{
nums1[k--]=nums1[l]>nums2[r]?nums1[l--]:nums2[r--];
}
while(r>=0)
{
nums1[k--]=nums2[r--];
}
}
};
- 平方数之和
long r=(int)sqrt(c);
-
sqrt是开方,返回数据类型为double,因此进行强制类型转换。
-
在枚举 aa 的同时,使用 \texttt{sqrt}sqrt 函数找出 bb。注意:本题 cc 的取值范围在 [0,2^{31} - 1]
[0,2^31 −1],因此在计算的过程中可能会发生 int 型溢出的情况,需要使用 long 型避免溢出。
- 验证回文字符串 Ⅱ
- 灵活使用bool类型,注意字符串操作用法。
class Solution {
public:
bool validPalindrome(string s) {
int left = 0;
int right = s.length() - 1;
while (left < right) {
if (s[left] == s[right]) {
left++;
right--;
} else {
return (check(left, right - 1, s) || check(left + 1, right, s));
}
}
return true;
}
bool check(int left, int right, string &s) {
while (left < right) {
if (s[left] != s[right]) {
return false;
}
left++;
right--;
}
return true;
}
};
- 通过删除字母匹配到字典里最长单词
- lamada匿名函数的使用,用&可以加快运算效率,a.size()和a.length()没什么区别。
class Solution {
public:
bool isSubsequence(string s, string t) {
int n=t.length();
int m=s.length();
int l=0;
int r=0;
while(l<m&&r<n)
{
if(s[l]==t[r])
{
r++;
}
l++;
}
return r==n;
}
string findLongestWord(string s, vector<string>& dictionary) {
sort(dictionary.begin(),dictionary.end(),[&](string &a,string &b){
if(a.size()==b.size())
{
return a<b;
}
return a.size()>b.size();
});
int k=dictionary.size();
for(int i=0;i<k;i++)
{
if(isSubsequence(s,dictionary[i]))
{
return dictionary[i];
}
}
return "";
}
};
二分查找法
- 二分查找
- 考虑区间开闭,经常用其思想,变种使用
- 一般使用与给定数组有序,时间复杂度为logn
int search(vector<int>& nums, int target) {
int n=nums.size();
int l=0;
int r=n-1;
while(l<=r)
{
int mid=l+(r-l)/2;
if(nums[mid]<target)
{
l=mid+1;
}
else if(nums[mid]>target)
{
r=mid-1;
}
else{
return mid;
}
}
return -1;
前缀和的思想,补一个位子
- 区域和检索 - 数组不可变
class NumArray {
public:
vector<int> array;
NumArray(vector<int>& nums) {
array.resize(nums.size()+1);
for(int i=0;i<nums.size();++i){
array[i+1]=nums[i]+array[i];
}
}
int sumRange(int left, int right) {
return array[right+1]-array[left];
}
};
- 有序数组中的单一元素
- 利用按位异或的性质,可以得到mid 和相邻的数之间的如下关系,其中 \oplus⊕ 是按位异或运算符:
- 当 mid 是偶数时,mid+1=mid⊕1;
当 mid 是奇数时,mid−1=mid⊕1。
例如:
4^1=5
3^1=2
因此在代码中直接使用了mid 和 mid^1 作为进行比较的两个下标,不需要再判断 mid 的奇偶性,代码更加简洁。
- 考虑mid 和 1 按位与运算的结果,其中 & 是按位与运算符:
当mid 是偶数时,mid & 1=0;
当 mid 是奇数时, mid & 1=1。
因此在得到mid 的值之后,将mid 的值减去mid & 1,即可确保 mid 是偶数,如果原来的mid 是偶数则值不变,如果原来的mid 是奇数则值减 1。
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int low = 0, high = nums.size() - 1;
while (low < high) {
int mid = (high - low) / 2 + low;
mid -= mid & 1;
if (nums[mid] == nums[mid + 1]) {
low = mid + 2;
} else {
high = mid;
}
}
return nums[low];
}
};