本篇主要是介绍leetcode中学习计划中算法入门的部分。
文章目录
- 一、二分查找
- 二、双指针
- 三、滑动窗口
- 四、广度优先遍历/深度优先遍历
- 五、递归/回溯
- 六、动态规划
- 七、位运算
一、二分查找
1、二分查找OJ链接
class Solution {
public:
int search(vector<int>& nums, int target) {
if(nums.empty()) return -1;
int begin=0;
int end=nums.size()-1;
int mid;
while(begin<=end)
{
mid=(begin+end)>>1;
if(target<nums[mid]) end=mid-1;
else if(target>nums[mid]) begin=mid+1;
else return mid;
}
return -1;
}
};
2、第一个错误的版本OJ链接
// The API isBadVersion is defined for you.
// bool isBadVersion(int version);
class Solution {
public:
int firstBadVersion(int n) {
//需要将数据类型换成long long 型不然会发生栈溢出
long long begin=0;
long long end=n;
long long mid;
while(begin<=end)
{
mid=(begin+end)>>1;
if(isBadVersion(mid)) end=mid-1;
else begin=mid+1;
}
return begin;
}
};
3、搜索插入位置OJ链接
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int begin=0;
int end=nums.size()-1;
int mid;
//利用二分查找的思路,如果没有找到则只需要返回begin即可
while(begin<=end)
{
mid=(begin+end)>>1;
if(nums[mid]<target) begin=mid+1;
else if(nums[mid]>target) end=mid-1;
else if(nums[mid]==target) return mid;
}
return begin;
}
};
二、双指针
1、有序数组的平方 OJ链接
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
if(nums.empty())
return vector<int>();
vector<int> newNums(nums.size(),0);
int i=0;
for(auto&e :nums)
{
newNums[i]=pow(e,2);
i++;
}
sort(newNums.begin(),newNums.end());
return newNums;
}
};
2、轮转数组OJ链接
class Solution {
public:
void rotate(vector<int>& nums, int k) {
if(nums.empty())
return;
k=k%nums.size();
//首先进行整体逆置
reverse(nums.begin(),nums.end());
reverse(nums.begin(),nums.begin()+k);
reverse(nums.begin()+k,nums.end());
}
};
3、移动零OJ链接
class Solution {
public:
void moveZeroes(vector<int>& nums) {
//如果此时为空说明则直接返回
if(nums.empty()) return;
//定义两个来确保非零元素的相对顺序
int begin=0;
int end=0;
//遍历操作来京所有0移动到数组的末尾
while(end<nums.size())
{
if(nums[end])
swap(nums[begin++],nums[end]);
end++;
}
}
};
4、两树之和II-输入有序数组OJ链接
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int begin=0;
int end=numbers.size()-1;
vector<int> result;
while(begin<end)
{
int sum=numbers[begin]+numbers[end];
if(sum>target)
{
end--;
}
else if(sum<target)
{
begin++;
}
else
{
//这里利用了C++11中的{}
return {begin+1,end+1};
}
}
return {-1,-1};
}
};
5、反转字符串 OJ链接
class Solution {
public:
void reverseString(vector<char>& s) {
int begin=0;
int end=s.size()-1;
while(begin<end)
{
swap(s[begin++],s[end--]);
}
}
};
6、反转字符串中的单词III OJ链接
class Solution {
public:
string reverseWords(string s) {
string newStr;
for(int i=0;i<s.size();i++)
{
string tmp="";
while(!isspace(s[i])&&i<s.size())
{
tmp+=s[i];
i++;
}
reverse(tmp.begin(),tmp.end());
newStr+=tmp;
if(s[i]!='\0')
newStr+=' ';
tmp="";
}
return newStr;
}
};
7、链表的中间节点 OJ链接
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode*fast=head;
ListNode*slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
};
8、删除链表中的倒数第N个结点OJ链接
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
ListNode*slow,*fast;//设置快慢指针进行求解
slow=fast=pListHead;
while(k--)//该步骤主要是使slow与fast指针之间的距离保持为k个单位
{
if(fast==nullptr)//若该链表中倒数第k个节点不存在则会返回nullptr该步骤需要进行判断
return nullptr;
fast=fast->next;
}
while(fast)//进行遍历操作对于slow和fast指针进行操作
{
slow=slow->next;
fast=fast->next;
}
return slow;
}
ListNode* removeNthFromEnd(ListNode* head, int n)
{
if(head->next==nullptr)
return nullptr;
ListNode*cur=head;
ListNode*prev=nullptr;
while(cur)
{
if(cur==FindKthToTail(head,n))
{
if(prev==nullptr)
head=head->next;
else
prev->next=cur->next;
}
prev=cur;
cur=cur->next;
}
return head;
}
};
三、滑动窗口
1、无重复字符的最长子串OJ链接
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.empty())
return 0;
//利用哈希表来查找当前的窗口是否存在重复的字符
unordered_map<char,int> HashTable;
//定义左右边界来进行判断窗口的大小
int left=0;
int right=0;
int MaxLength=0;
while(right<s.size()){
if(HashTable.find(s[right])!=HashTable.end()&&left<=HashTable[s[right]])
left=HashTable[s[right]]+1;
if(right-left+1>MaxLength)
MaxLength=right-left+1;
HashTable[s[right]]=right;
right++;
}
return MaxLength;
}
};
2、字符串的排列OJ链接
class Solution {
public:
bool checkInclusion(string s1, string s2) {
//利用哈希表来判断s2窗口中s1字符串中出现的次数
unordered_map<char,int> HashTable1;
unordered_map<char,int> HashTable2;
//s1的种类
int Count=0;
for(int i=0;i<s1.size();i++){
if(HashTable1.find(s1[i])==HashTable1.end())
Count++;
HashTable1[s1[i]]++;
}
int WindowCount=0;
int left=0;
int right=0;
//遍历字符串s2中来滑动窗口
while(right<s2.size()){
if(HashTable1[s2[right]]>0){
HashTable2[s2[right]]++;
if(HashTable1[s2[right]]==HashTable2[s2[right]])
WindowCount++;
}
right++;
while(Count==WindowCount){
if(right-left==s1.size()) return true;
if(HashTable1[s2[left]]>0){
HashTable2[s2[left]]--;
if(HashTable2[s2[left]]<HashTable1[s2[left]])
WindowCount--;
}
left++;
}
}
return false;
}
};
四、广度优先遍历/深度优先遍历
1、图形渲染OJ链接
int nextp[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
class Solution {
public:
void DFS(vector<vector<int>>&image,vector<vector<bool>>&visited,int sr,int sc,int oldColor,int color)
{
image[sr][sc]=color;
visited[sr][sc]=true;
for(int i=0;i<4;i++){
int newX=sr+nextp[i][0];
int newY=sc+nextp[i][1];
if(newX<0||newX>=image.size()||newY<0||newY>=image[0].size())
continue;
if(image[newX][newY]==oldColor&&visited[newX][newY]==false)
DFS(image,visited,newX,newY,oldColor,color);
}
}
vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) {
if(image.empty())
return vector<vector<int>>();
vector<vector<bool>> visited(image.size(),vector<bool>(image[0].size(),false));
int oldColor=image[sr][sc];
DFS(image,visited,sr,sc,oldColor,color);
return image;
}
};
2、岛屿的最大面积 OJ链接
int nextp[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
class Solution {
public:
int DFS(vector<vector<int>>&grid,vector<vector<bool>>&visited,int sr,int sc){
int s=0;
if(grid[sr][sc]==1)
s++;
visited[sr][sc]=true;
for(int k=0;k<4;k++)
{
int newX=sr+nextp[k][0];
int newY=sc+nextp[k][1];
if(newX<0||newX>=grid.size()||newY<0||newY>=grid[0].size()||visited[newX][newY])
continue;
if(grid[newX][newY]==1)
s+=DFS(grid,visited,newX,newY);
}
return s;
}
int maxAreaOfIsland(vector<vector<int>>& grid) {
vector<vector<bool>> visited(grid.size(),vector<bool>(grid[0].size(),false));
int MaxArea=0;
for(int i=0;i<grid.size();i++)
for(int j=0;j<grid[i].size();j++)
if(grid[i][j]==1)
MaxArea=max(MaxArea,DFS(grid,visited,i,j));
return MaxArea;
}
};
3、合并二叉树OJ链接
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if(root1==nullptr)
return root2;
if(root2==nullptr)
return root1;
TreeNode*merge=new TreeNode(root1->val+root2->val);
merge->left=mergeTrees(root1->left,root2->left);
merge->right=mergeTrees(root1->right,root2->right);
return merge;
}
};
4、填充每个节点的下一个右侧节点OJ链接
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
*/
class Solution {
public:
Node* connect(Node* root) {
if(root==nullptr)
return nullptr;
queue<Node*> q;
q.push(root);
while(!q.empty())
{
int size=q.size();
for(int i=0;i<size;i++){
Node*front=q.front();
q.pop();
if(i<size-1)
front->next=q.front();
if(front->left)
q.push(front->left);
if(front->right)
q.push(front->right);
}
}
return root;
}
};
5、矩阵OJ链接
int nextp[4][2]= {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
class Solution {
private:
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
int row=mat.size();
int col=mat[0].size();
vector<vector<int>> result(row, vector<int>(col,0));
vector<vector<bool>> visited(row, vector<bool>(col,false));
queue<pair<int, int>> q;
// 将所有的 0 添加进初始队列中
for (int i = 0; i < row; ++i) {
for (int j = 0; j < col; ++j) {
if (mat[i][j] == 0) {
q.push(make_pair(i,j));
visited[i][j] = true;
}
}
}
// 广度优先搜索
while (!q.empty()) {
pair<int,int> Pos= q.front();
q.pop();
for (int d = 0; d < 4; ++d) {
int newX = Pos.first + nextp[d][0];
int newY = Pos.second + nextp[d][1];
if (newX >= 0 &&newX < row && newY>= 0 &&newY < col&&visited[newX][newY]==false ) {
result[newX][newY] = result[Pos.first][Pos.second] + 1;
q.push(make_pair(newX, newY));
visited[newX][newY] = true;
}
}
}
return result;
}
};
6、腐烂的橘子OJ链接
int nextp[4][2]={{1,0},{0,1},{0,-1},{-1,0}};
class Solution {
public:
int orangesRotting(vector<vector<int>>& grid) {
//利用pair来存储位置信息
queue<pair<int,int>> q;
int row=grid.size();
int col=grid[0].size();
//第一步将腐烂的橘子进行入队操作
for(int i=0;i<row;i++)
for(int j=0;j<col;j++)
if(grid[i][j]==2)
q.push(make_pair(i,j));
//进行蔓延的方向
int times=0;
while(!q.empty()){
int size=q.size();
int flag=0;//定义一个flag来判断是否是有新橘子被腐烂
for(int i=0;i<size;i++){
pair<int,int> Curpos=q.front();
q.pop();
for(int i=0;i<4;i++){
int newX=Curpos.first+nextp[i][0];
int newY=Curpos.second+nextp[i][1];
//如果此时的位置中存在越界或者是该位置上面的橘子已经被腐烂过则跳过此次
if(newX>=row||newY>=col||newX<0||newY<0||grid[newX][newY]!=1)
continue;
flag=1;
grid[newX][newY]=2;
q.push(make_pair(newX,newY));
}
}
if(flag)
++times;
}
//最后需要进行判断是否还存在无法腐烂的橘子
for(int i=0;i<row;i++)
for(int j=0;j<col;j++)
if(grid[i][j]==1)
return -1;
return times;
}
};
五、递归/回溯
1、合并两个有序链表OJ链接
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
0* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
//将野指针的问题单独处理一下
if(list1==nullptr)
return list2;
if(list2==nullptr)
return list1;
ListNode*head,*tail;
head=nullptr;
tail=nullptr;
//利用归并的思路 从头开始比较取小的尾插到新链表
while(list1&&list2)//遍历两个有序链表
{
if(list1->val<list2->val)
{
if(tail==nullptr)
head=tail=list1;
else
{
tail->next=list1;
tail=tail->next;
}
list1=list1->next;
}
else
{
if(tail==nullptr)
{
head=tail=list2;
}
else
{
tail->next=list2;
tail=tail->next;
}
list2=list2->next;
}
}
if(list1)//list1不为空时将list1中后面的节点尾插
tail->next=list1;
if(list2)//同理
tail->next=list2;
return head;
}
};
2、反转链表OJ链接
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* BuySListNode(int x)
{
ListNode* node = new ListNode;
node->val = x;
node->next = NULL;
return node;
}
ListNode* reverseList(ListNode* head) {
ListNode*cur1=head;
ListNode*cur2=head;
int length=0;
while(cur1)
{
length++;
cur1=cur1->next;
}
vector<int>v;
v.reserve(length);
while(cur2)
{
v.push_back(cur2->val);
cur2=cur2->next;
}
reverse(v.begin(),v.end());
ListNode*newnode=new ListNode;
ListNode*curNode=newnode;
for(int i=0;i<v.size();i++)
{
ListNode* node = BuySListNode(v[i]);
curNode->next = node;
curNode=curNode->next;
}
return newnode->next;
}
};
3、组合OJ链接
vector<int> tmp;
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> result;
DFS(result,n,k,1);
return result;
}
void DFS(vector<vector<int>>&result,int n,int k,int start){
if(tmp.size()==k){
result.push_back(tmp);
return;
}
for(int i=start;i<=n;i++){
tmp.push_back(i);
DFS(result,n,k,i+1);
tmp.pop_back();
}
}
};
4、全排列OJ链接
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> result;
vector<bool> visited(nums.size(),false);
vector<int> tmp;
DFS(nums,result,visited,tmp);
return result;
}
void DFS(vector<int>&nums,vector<vector<int>>&result,vector<bool>&visited,vector<int>&tmp)
{
if(tmp.size()==nums.size())
{
result.push_back(tmp);
return;
}
for(int i=0;i<nums.size();i++)
{
if(visited[i]==true)
continue;
else
{
tmp.push_back(nums[i]);
visited[i]=true;
DFS(nums,result,visited,tmp);
tmp.pop_back();
visited[i]=false;
}
}
}
};
5、字母大小写全排列OJ链接
class Solution {
public:
void DFS(string&s,int startIndex,vector<string>&result,string&tmp)
{
if(tmp.size()==s.size()){
result.push_back(tmp);
return;
}
if(isdigit(s[startIndex])){
tmp.push_back(s[startIndex]);
DFS(s,startIndex+1,result,tmp);
tmp.pop_back();
}
if(isalpha(s[startIndex]))
{
tmp.push_back(toupper(s[startIndex]));
DFS(s,startIndex+1,result,tmp);
tmp.pop_back();
tmp.push_back(tolower(s[startIndex]));
DFS(s,startIndex+1,result,tmp);
tmp.pop_back();
}
}
vector<string> letterCasePermutation(string s) {
vector<string> result;
string tmp="";
DFS(s,0,result,tmp);
return result;
}
};
六、动态规划
1、爬楼梯OJ链接
class Solution {
public:
int climbStairs(int n) {
vector<int> dp(n+2,0);
dp[1]=1;
dp[2]=2;
for(int i=3;i<=n;i++)
dp[i]=dp[i-1]+dp[i-2];
return dp[n];
}
};
2、打家劫舍OJ链接
class Solution {
public:
int rob(vector<int>& nums) {
if(nums.empty())
return 0;
//如果只有一个元素直接返回第一个元素的值不然后面会造成非法访问
if(nums.size()==1)
return nums[0];
int *dp=(int*)malloc(sizeof(int)*nums.size());
dp[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
for(int i=2;i<nums.size();i++)
dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
return dp[nums.size()-1];
}
};
3、三角形最小路径和OJ链接
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
//第一种方式:
for(int i=1;i<triangle.size();i++)
for(int j=0;j<triangle[i].size();j++)
{
if(j==0)
triangle[i][j]=triangle[i-1][j]+triangle[i][j];
else if(i==j)
triangle[i][j]=triangle[i-1][j-1]+triangle[i][j];
else
triangle[i][j]=min(triangle[i-1][j-1],triangle[i-1][j])+triangle[i][j];
}
int MinPath=triangle[triangle.size()-1][0];
for(int i=1;i<triangle[triangle.size()-1].size();i++)
MinPath=min(triangle[triangle.size()-1][i],MinPath);
return MinPath;
}
};
七、位运算
1、2的幂OJ链接
class Solution {
public:
bool isPowerOfTwo(int n) {
return n>0&&(n&(n-1))==0;
}
};
2、位1的个数OJ链接
class Solution {
public:
int hammingWeight(uint32_t n) {
bitset<32> num(n);
return num.count();
}
};
3、颠倒二进制位OJ链接
class Solution {
public:
uint32_t reverseBits(uint32_t n){
bitset<32> num(n);
string str;
str=num.to_string();
reverse(str.begin(),str.end());
bitset<32> dst(str);
return dst.to_ulong();
}
};
4、只出现一次的数字OJ链接
class Solution {
public:
int singleNumber(vector<int>& nums) {
int count=0;
for(auto e:nums)
count^=e;
return count;
}
};