1.二分查找
有两种写法
第一种:左闭右闭
第二种:左闭右开
两种方法注意初始化 right的不同 以及更新right的不同
第一种:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size()-1;
while(left<=right){
int mid = (left+right)/2;
if(target>nums[mid]){
left=mid+1;
}else if(target<nums[mid]){
right=mid-1;;
}else{
return mid;
}
}
return -1;
}
};
第二种:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size();
while(left<right){
int mid = (left+right)/2;
if(target>nums[mid]){
left=mid+1;
}else if(target<nums[mid]){
right=mid;;
}else{
return mid;
}
}
return -1;
}
};
2.移除元素
这里用快慢指针
slowindex 指向将要填的位置
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowindex =0;
int fastindex =0;
for(int fastindex =0;fastindex<nums.size();fastindex++){
if(nums[fastindex]!=val){
nums[slowindex] = nums[fastindex];
slowindex++;
}
}
return slowindex;
}
};
3.有序数组的平方
思路:每次可以获取最大值
a.用双指针 i,j i指向头 j指向尾 平方后比较大小 大的直接放到新的数组中 新数组从尾部开始放
int i=0;
int j=nums.size()-1;
完整代码
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int i=0;
int j=nums.size()-1;
int k =nums.size()-1;
vector<int> result(nums.size(),0);
while(i<=j){
if(pow(nums[i],2) >pow(nums[j],2) ){
result[k] = nums[i]*nums[i];
k--;
i++;
}else{
result[k] = nums[j]*nums[j];
k--;
j--;
}
}
return result;
}
};
b.用双指针 i,j i指向头 j指向尾 平方后比较大小 大的直接放到栈中 最后结果从栈顶到栈底依次输出即可
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int left =0;
int right = nums.size()-1;
stack<int> st;
while(left<=right){
if(abs(nums[left]) > abs(nums[right])){
st.push(pow(nums[left],2));
left++;
}else if(abs(nums[left]) < abs(nums[right])){
st.push(pow(nums[right],2));
right--;
}else{
st.push(pow(nums[left],2));
left++;
}
}
vector<int> res;
while(!st.empty()){
res.push_back(st.top());
st.pop();
}
return res;
}
};
4.长度最小的子数组
需要
使用双指针法 j指针遍历数组nums[i] j管理右边界 每次遍历都加一,low管理左边界 左边界需要判断sum是否符合条件 因此左边界可能不止加一。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int i=0;
int sum = 0;
int minlen =INT_MAX;
for(int j=0;j<nums.size();j++){
sum=sum+nums[j];
while(sum>=target){
minlen=min(minlen,j-i+1);
sum=sum-nums[i];
i++;
}
}
return minlen==INT_MAX? 0:minlen;
}
};
5.螺旋矩阵II
直接使用图查找
class Solution {
public:
vector<vector<int>> dxy{{0,1},{1,0},{0,-1},{-1,0}};
bool isValid(vector<vector<int>> matrix,int x, int y){
if(x<0||x>=matrix.size() || y<0 || y>=matrix[0].size()){
return false;
}
if(matrix[x][y]!=0){
return false;
}
return true;
}
void backtracking(vector<vector<int>>& matrix,int stari, int starj,int fangxiang,int value){
for(int i=0;i<4;i++){
int newfangxiang = (fangxiang+i)%4;
// cout<<"newfangxiang:"<<newfangxiang<<endl;
int x = stari+dxy[newfangxiang][0];
int y = starj+dxy[newfangxiang][1];
if(!isValid(matrix, x, y)){
continue;
}
matrix[x][y] = value;
backtracking(matrix,x,y,newfangxiang,value+1);
// matrix[x][y] = 0;
}
}
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> matrix(n,vector<int>(n,0));
int fangxiang=0;
matrix[0][0]=1;
backtracking(matrix,0,0,fangxiang,2);
return matrix;
}
};
数组题目补充:
6-12是一类题目
6.只出现一次的数字
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ret=0;
for(auto num:nums){
ret=ret^num;
}
return ret;
}
};
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param numbers int整型vector
* @return int整型
*/
int duplicate(vector<int>& numbers) {
// write code here
// 将数字放到自己的位置上面
for(int i=0;i<numbers.size();i++){
while(numbers[i]!=i){
if(numbers[i]==numbers[numbers[i]]){
return numbers[i];
}
swap(numbers[i],numbers[numbers[i]]);
}
}
return -1;
}
};
class Solution {
public:
vector<int> findDuplicates(vector<int>& nums) {
vector<int> ret;
for(auto &num:nums){
num=num-1;
}
for(int i=0;i<nums.size();i++){
while(nums[i]!=i){
if(nums[i]==-1){
break;
}
if(nums[i]==nums[nums[i]]){
ret.push_back(nums[i]+1);
nums[i]=-1;
}else{
swap(nums[i],nums[nums[i]]);
}
}
}
return ret;
}
};
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
for(auto &num:nums){
num=num-1;
}
for(int i=0;i<nums.size();i++){
while(nums[i]!=i){
if(nums[i]==-1){
break;
}
if(nums[i]!=nums[nums[i]]){
swap(nums[i],nums[nums[i]]);
}else{
nums[i]=-1;
}
}
}
vector<int> ret;
for(int i=0;i<nums.size();i++){
if(nums[i]==-1){
ret.push_back(i+1);
}
}
return ret;
}
};
10.丢失的数字(所有数字都不相同)
方法二:将对应的数字放到对应的位置上面 发现可能越界的数据 直接break;
class Solution {
public:
int missingNumber(vector<int>& nums) {
for(int i=0;i<nums.size();i++){
while(nums[i]!=i){
if(nums[i]==nums.size()){
break;
}
swap(nums[i],nums[nums[i]]);
}
}
for(int i=0;i<nums.size();i++){
if(nums[i]!=i){
return i;
}
}
return nums.size();
}
};
方法二:抓住题目说的所有的数字都不会重复 先将0-n全部累加起来 sum 按照题意缺失的数字是 sum-count(nums)
class Solution {
public:
int missingNumber(vector<int>& nums) {
// 先将0-n全部累加起来 sum 按照题意缺失的数字是 sum-count(nums)
int sum =0;
for(int i=0;i<=nums.size();i++){
sum=sum+i;
}
for(auto num:nums){
sum=sum-num;
}
return sum;
}
};
11.缺失的第一个正数
显然需要将nums[i] 放到nums[i] -1的位置上面 (正整数从1开始) 为了方便先将nums全部减1
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
for(auto &num:nums){
num=(long)num-1;
}
for(int i=0;i<nums.size();i++){
while(nums[i]!=i){
if(nums[i]<0||nums[i]>=nums.size()){
break;
}
if(nums[i]!=nums[nums[i]]){
swap(nums[i],nums[nums[i]]);
}else{
nums[i]=-1;
}
}
}
for(int i=0;i<nums.size();i++){
cout<<" "<<nums[i];
}
for(int i=0;i<nums.size();i++){
if(nums[i]!=i ){
return i+1;
}
}
return nums.size()+1;
}
};
12. 剑指 Offer 53 - II. 0~n-1中缺失的数字(有序排列 )
思路:因为按照题目已经是有序的的 直接用二分检查是否在对应位置
class Solution {
public:
int takeAttendance(vector<int>& records) {
// 左边界是最小编号
int left =0;
// 右边界是 最大编号
int right =records.size();
while(left<right){
int mid = (left+right)/2;
if(mid<records[mid]){
// 可能是结果
right=mid;
}else if(records[mid]==mid){
// 可能结果只能在右边
left=mid+1;
}
// 不可能出现这种情况
// else if(records[mid]>mid){
// }
}
return left;
}
};
有序数组中的单一元素(二分法)
思路:题目说有序了 并且需要查找某个元素 想到二分 查找元素一定在偶数位上面 并且满足nums[mid]!=mis[mid+1] 但是满足nums[mid]!=mis[mid+1] 的下标位置有可能是结果而已 需要压缩空间 right =mid;这题要点就是当nums[mid]==mis[mid+1] left=mid+2不然会死循环的
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int left =0;
int right = nums.size()-1;
while(left<right){
int mid =(left+right)/2;
if(mid%2!=0){
mid--;
}
if(nums[mid]==nums[mid+1]){
left = mid+2;
}else if(nums[mid]!=nums[mid+1]){
right =mid;
}
}
return nums[left];
}
};
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型vector
* @return int整型vector
*/
vector<int> FindNumsAppearOnce(vector<int>& nums) {
// write code here
int res =0;
for(auto num:nums){
res=res^num;
}
// 找到第一个是1的位置
int oneplace =1;
cout<<"res:"<<res<< " oneplace:"<<oneplace<<endl;
while((oneplace&res)==0){
cout<<"oneplace:"<<oneplace<<endl;
oneplace=oneplace<<1;
}
cout<<"res:"<<res<< " oneplace:"<<oneplace<<endl;
int a=0,b=0;
for(auto num:nums){
if((num&oneplace)==0){
a=a^num;
}else{
b=b^num;
}
}
if(a<b){
return {a,b};
}
return {b,a};
}
};
14.青蛙过河
思路:也就是找到最后一个石头 是否有其他位置可以到达 从前向后遍历 每次遍历当前石头数值 以及当前石头可以跳到下一个节点的jmp …
class Solution {
public:
bool canCross(vector<int>& stones) {
unordered_map<int,unordered_set<int>> mymap;
for(auto value:stones){
unordered_set<int> myset;
mymap[value]=myset;
}
mymap[0].insert(0);
// 遍历石头数值
for(auto value:stones){
unordered_set<int> myset = mymap[value];
// 可以到达当前石头数值的跳跃步数
for(int jmp:myset){
// 遍历我们可以从当前石头跳到下个数值的步数
for(int k=jmp-1;k<=jmp+1;k++){
// 存在可以跳到后面数值的步数
if(k>0&&mymap.count(value+k)>0){
mymap[value+k].insert(k);
}
}
}
}
// 最后一个石头是否可达
return mymap[stones.back()].size()>0?true:false;
}
};
15.排序矩阵查找
思路:根据题目意思 直接从右上角开始找 小的在左边 大的在下边
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if(matrix.size()==0||matrix[0].size()==0){
return 0;
}
int i=0;
int j=matrix[0].size()-1;
while(i<matrix.size()&&j>=0){
if(target>matrix[i][j]){
i++;
}else if(target<matrix[i][j]){
j--;
}else{
return true;
}
}
return false;
}
};
16.求x的开根号值
方法一:最后直接打补丁
class Solution {
public:
int mySqrt(int x) {
int left =0;
int right =x;
while(left<right){
int mid =(left+right)/2;
if((long)mid*mid>x){
right=mid -1;
}else if(mid*mid<x){
left = mid+1;
}else{
return mid;
}
cout<<"left:"<<left<<"right:"<<right<<endl;
}
return (long)left*left>x?left-1:left;
}
};
方法二:
class Solution {
public:
int mySqrt(int x) {
// 找到 x 的平方根(左侧最后一个下标)
// 左侧:nums[i]^2 <= x
// 右侧:nums[i]^2 > x
int l = 0, r = x;
while (l < r) {
int mid=(l+r+1)/2;
if ((long)mid*mid <= x){
l = mid;
} else{
r = mid - 1;
}
}
return l;
}
};
17.寻找峰值
class Solution {
public:
int findPeakElement(vector<int>& nums)
{
int left=0;
int right = nums.size()-1;
while(left<right){
int mid=(left+right)/2;
if(nums[mid]>nums[mid+1]){
right =mid;
}else if(nums[mid]<nums[mid+1]){
left = mid+1;
}
cout<<left<<" "<<right<<endl;
}
return left;
}
};
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型vector
* @return int整型
*/
int minNumberInRotateArray(vector<int>& nums) {
int left = 0;
int right = nums.size()-1;
while(left<right){
int mid = (left+right)/2;
if(nums[mid]>nums[right]){
left=mid +1;
}else if(nums[mid]<nums[right]){
right =mid;
}else if(nums[mid]==nums[right]){
right--;
}
}
return nums[left];
}
};