方法一 .常规方法
class Solution {
public:
int strStr(string haystack, string needle) {
if(haystack.empty() && needle.empty()) return 0;
int m = haystack.length();
int n = needle.length();
for(int i=0;i+n<=m;++i)
{
bool flag = true;
for(int j=0;j
方法二.KMP算法
【宫水三叶】简单题学 KMP 算法 - 实现 strStr() - 力扣(LeetCode) (leetcode-cn.com)
class Solution {
public:
int strStr(string haystack, string needle) {
int n = haystack.size();
int m = needle.size();
if(m == 0) return 0;
vector next(m);
for(int i=1,j=0;i0 && needle[i] != needle[j])
{
j = next[j-1];
}
if(needle[i] == needle[j])
{
++j;
}
next[i] = j;
}
for(int i =0,j=0;i0 && haystack[i] != needle[j])
{
j = next[j-1];
}
if(haystack[i] == needle[j])
{
++j;
}
if(j == m)
{
return i-m+1;
}
}
return -1;
}
}
class Solution {
public:
int myAtoi(string s) {
int n = s.length();
if(n == 0) return 0;
int index = 0;
while(index Integer.MAX_VALUE
但是 *10 和 + digit 都有可能越界,所有都移动到右边去就可以了。*/
if(ans > (INT_MAX-num)/10)
{
return flag?INT_MAX:INT_MIN;
}
ans = ans*10+num;
index++;
}
return flag?ans:-ans;
}
};
class Solution {
public:
vector> threeSum(vector& nums)
{
int size = nums.size();
if (size < 3) return {}; // 特判
vector >res; // 保存结果(所有不重复的三元组)
std::sort(nums.begin(), nums.end());// 排序(默认递增)
for (int i = 0; i < size; i++) // 固定第一个数,转化为求两数之和
{
if (nums[i] > 0) return res; // 第一个数大于 0,后面都是递增正数,不可能相加为零了
// 去重:如果此数已经选取过,跳过
if (i > 0 && nums[i] == nums[i-1]) continue;
// 双指针在nums[i]后面的区间中寻找和为0-nums[i]的另外两个数
int left = i + 1;
int right = size - 1;
while (left < right)
{
if (nums[left] + nums[right] + nums[i] > 0)
right--; // 两数之和太大,右指针左移
else if (nums[left] + nums[right] + nums[i] < 0)
left++; // 两数之和太小,左指针右移
else
{
// 找到一个和为零的三元组,添加到结果中,左右指针内缩,继续寻找
res.push_back({nums[i], nums[left], nums[right]});
left++;
right--;
// 去重:第二个数和第三个数也不重复选取
// 例如:[-4,1,1,1,2,3,3,3], i=0, left=1, right=5
while (left < right && nums[left] == nums[left-1]) left++;
while (left < right && nums[right] == nums[right+1]) right--;
}
}
}
return res;
}
};
class Solution {
public:
int threeSumClosest(vector& nums, int target) {
int n = nums.size();
sort(nums.begin(),nums.end());
int pre = nums[0]+nums[1]+nums[2];
for(int i = 0;i target) --right;
else if(cur < target) ++left;
else return target;
}
}
return pre;
}
};
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
ListNode* newhead = new ListNode();
newhead->next = head;
ListNode* pre = newhead;
for(int i=0;inext;
}
ListNode* cur = pre->next;
ListNode* next;
for(int i=0;inext;
cur->next = next->next;
next->next = pre->next;
pre->next = next;
}
return newhead->next;
}
};
class Solution {
public:
int subarraySum(vector& nums, int k) {
unordered_map m;
m[0] = 1;
int ans = 0;
int sum = 0;
for(auto &x:nums)
{
sum+=x;
if(m.find(sum-k) != m.end())
{
ans+=m[sum-k];
}
m[sum]++;
}
return ans;
}
};
class Solution {
public:
int sum = 0;
TreeNode* convertBST(TreeNode* root) {
if (root != nullptr) {
convertBST(root->right);
sum += root->val;
root->val = sum;
convertBST(root->left);
}
return root;
}
};
给你两个整数 a
和 b
,不使用 运算符 +
和 -
,计算并返回两整数之和。
class Solution {
public:
int getSum(int a, int b) {
while(b!=0)
{
unsigned int carry = (unsigned int)(a & b)<<1;//进位
a^=b;
b = carry;
}
return a;
}
};
class Trie {
private:
vector children;
bool isEnd;
Trie* searchPrefix(string prefix) {
Trie* node = this;
for (char ch : prefix) {
ch -= 'a';
if (node->children[ch] == nullptr) {
return nullptr;
}
node = node->children[ch];
}
return node;
}
public:
Trie() : children(26), isEnd(false) {}
void insert(string word) {
Trie* node = this;
for (char ch : word) {
ch -= 'a';
if (node->children[ch] == nullptr) {
node->children[ch] = new Trie();
}
node = node->children[ch];
}
node->isEnd = true;
}
bool search(string word) {
Trie* node = this->searchPrefix(word);
return node != nullptr && node->isEnd;
}
bool startsWith(string prefix) {
return this->searchPrefix(prefix) != nullptr;
}
};
class Solution {
public:
int rob(vector& nums) {
int n = nums.size();
if(n == 0) return 0;
if(n == 1) return nums[0];
vector dp(n);
dp[0] = nums[0];
dp[1] = max(nums[0],nums[1]);
for(int i = 2;i
class Solution {
public:
int countPrimes(int n) {
vector isPrime(n,true);
int ans = 0;
for (int i = 2; i < n; ++i) {
if(isPrime[i])
{
ans++;
for(int j=2;i*j
class Solution {
public:
int maximalSquare(vector>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
if(m == 0 || n == 0) return 0;
vector> dp(m,vector(n));
int ans = 0;
for(int i=0;i
class Solution {
public:
int countSquares(vector>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
vector> dp(m,vector(n));
int ans = 0;
for(int i=0;i
class Solution {
public:
int rob(vector& nums) {
if (nums.size() == 0) return 0;
if (nums.size() == 1) return nums[0];
int result1 = robRange(nums, 0, nums.size() - 2); // 情况二
int result2 = robRange(nums, 1, nums.size() - 1); // 情况三
return max(result1, result2);
}
// 198.打家劫舍的逻辑
int robRange(vector& nums, int start, int end) {
if (end == start) return nums[start];
vector dp(nums.size());
dp[start] = nums[start];
dp[start + 1] = max(nums[start], nums[start + 1]);
for (int i = start + 2; i <= end; i++) {
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
}
return dp[end];
}
};
class Solution {
public:
int rob(TreeNode* root) {
vector ans = dfs(root);
return max(ans[0],ans[1]);
}
vector dfs(TreeNode* root)
{
if(root == nullptr) return vector{0,0};
vector left = dfs(root->left);
vector right = dfs(root->right);
int val1 = root->val + left[0] + right[0];
int val2 = max(left[0],left[1]) + max(right[0],right[1]);
return {val2,val1};
}
};
class Solution {
public:
vector removeInvalidParentheses(string s) {
vector ans;
unordered_set curset;
curset.insert(s);
while(true)
{
for(auto & str : curset)
{
if((isValid(str)))
{
ans.push_back(str);
}
}
if(!ans.empty()) return ans;
unordered_set nextstr;
for(auto &str:curset)
{
for(int i=0;i0 && str[i] == str[i-1]) continue;
if(str[i] == '(' || str[i] == ')')
{
nextstr.insert(str.substr(0,i)+str.substr(i+1,str.size()));
}
}
}
curset = nextstr;
}
}
bool isValid(string str)
{
int count =0 ;
for(auto &x:str)
{
if(x == '(') count++;
else if(x == ')')
{
count--;
if(count < 0) return false;
}
}
return count == 0;
}
};
详情参考
class Solution {
public:
int largestRectangleArea(vector& heights) {
stack st;
int result = 0;
heights.insert(heights.begin(), 0);
heights.push_back(0);
// 第一个元素已经入栈,从下表1开始
for (int i = 0; i < heights.size(); i++) {
while (!st.empty()&&heights[i] < heights[st.top()]) { // 注意是while
int curheight = heights[st.top()];
st.pop();
int cur = curheight*(i-st.top()-1);
result = max(result, cur);
}
st.push(i);
}
return result;
}
};
class Solution {
public:
int maximalRectangle(vector>& matrix) {
if(matrix.empty()) return 0;
int m = matrix.size();
int n = matrix[0].size();
int ans = 0;
vector heights(n+2);
for(int i=0;i& heights) {
stack st;
int result = 0;
// 第一个元素已经入栈,从下表1开始
for (int i = 0; i < heights.size(); i++) {
while (!st.empty()&&heights[i] < heights[st.top()]) { // 注意是while
int curheight = heights[st.top()];
st.pop();
int cur = curheight*(i-st.top()-1);
result = max(result, cur);
}
st.push(i);
}
return result;
}
};
class Solution {
public:
bool reorderedPowerOf2(int n) {
vector nums(10,0);
while(n)
{
nums[n%10]++;
n/=10;
}
for(int i=1;i<=1e9;i<<=1)//i*=2
{
vector temp(10,0);
int k = i;
while(k)
{
temp[k%10]++;
k/=10;
}
if(nums == temp) return true;
}
return false;
}
};
课程表 - 课程表 - 力扣(LeetCode) (leetcode-cn.com)
class Solution {
private:
vector> edges;
vector indeg;
vector ans;
public:
vector findOrder(int numCourses, vector>& prerequisites) {
edges.resize(numCourses);
indeg.resize(numCourses);
for(auto &x:prerequisites)
{
edges[x[1]].push_back(x[0]);
indeg[x[0]]++;
}
queue q;
for(int i=0;i
class Solution {
public:
bool wordBreak(string s, vector& wordDict) {
unordered_set st(wordDict.begin(),wordDict.end());
int n = s.size();
vector dp(n+1);
dp[0] = true;
for(int i=1;i<=n;++i)
{
for(int j=0;j
class Solution {
public:
vector ans;
string temp;
vector Map = {
"",
"",
"abc",
"def",
"ghi",
"jkl",
"mno",
"pqrs",
"tuv",
"wxyz"
};
vector letterCombinations(string digits) {
if(digits.empty()) return {};
func(digits,0);
return ans;
}
void func(string digits,int index)
{
if(index == digits.size())
{
ans.push_back(temp);
return ;
}
int ch = digits[index]-'0';
string s = Map[ch];
for(auto& x:s)
{
temp.push_back(x);
func(digits,index+1);
temp.pop_back();
}
}
};
class Solution {
public:
bool isPowerOfTwo(int n) {
return n>0 && (1<<30)%n == 0;//2的30次方对n取余
}
};
class Solution {
public:
int rand10() {
int num = (rand7() -1)*7 + rand7();
/*
(1-1)*7 + 1 = 1
(7-1)*7 + 7 = 42+7 = 49
1~49
*/
while(num > 40)//去除大于40的值,使1~40等概率出现
{
num = (rand7()-1)*7 +rand7();
}
return 1+num%10;//1+ (0~9)
}
};
class Solution {
public:
double findMedianSortedArrays(vector& nums1, vector& nums2) {
int length = nums1.size()+nums2.size();
if(length % 2 == 1)
{
return func(nums1,nums2,(length+1)/2);//此时要找的第K个数为(length+1)/2
}
else
{
return (func(nums1,nums2,length/2) + func(nums1,nums2,(length/2+1)))/2.0;
//此事要找的第K个数为 length/2 + length/2+1
}
}
int func(vector nums1,vector nums2,int k)
{
int len1 = nums1.size();
int len2 = nums2.size();
int i = 0;
int j = 0;
while(true)
{
if(i == len1)//如果第一个数组为空
{
return nums2[j+k-1];
}
if(j == len2)//如果第二个数组为空
{
return nums1[i+k-1];
}
if(k == 1)//如果要找的中位数即K为1,则返回当前遍历的nums1和nums2起始位置的较小值即可
{
return min(nums1[i],nums2[j]);
}
int half = k/2;
int I = min(i+half,len1)-1;
int J = min(j+half,len2)-1;
if(nums1[I] <= nums2[J])
{
k-=(I-i+1);
i = I+1;
}
else{
k-=(J-j+1);
j = J+1;
}
}
}
};
class Solution {
public:
vector> getSkyline(vector>& buildings) {
vector> sortedBuildings;
for(auto& x:buildings)
{
sortedBuildings.push_back(make_pair(x[0],-x[2]));
sortedBuildings.push_back(make_pair(x[1],x[2]));
}
sort(sortedBuildings.begin(),sortedBuildings.end(),[](auto& left,auto& right)
{
if(left.first == right.first)
{
return left.second < right.second;
}
return left.first < right.first;
});//按横坐标进行排序
multiset> pq;
pq.insert(0);
vector> ans;
for(auto& build:sortedBuildings)
{
int x = build.first;
int y = build.second;
int top = *(pq.begin());
if(y<0)//高度小于0,说明此为左节点
{
y=-y;
if(y>top)
{
ans.push_back({x,y});
}
pq.insert(y);
}
else//右节点
{
pq.erase(pq.find(y));
int temp = *(pq.begin());
if(top > temp)
{
ans.push_back({x,temp});
}
}
}
return ans;
}
};
class Solution {
public:
void hanota(vector& A, vector& B, vector& C) {
move(A.size(),A,B,C);//把A上的N个盘子通过B移到C A->B->C
}
void move(int n,vector& A,vector& B,vector& C)
{
if(n == 1)
{
C.push_back(A.back());
A.pop_back();
return ;
}
move(n-1,A,C,B);//把A上面的n-1个盘子通过C移动到B A->C->B
C.push_back(A.back());
A.pop_back();
move(n-1,B,A,C);//把B上面的n-1个盘子通过A移动到C B->A->C
}
};
class Solution {
public:
bool check(vector>& matrix, int mid, int k, int n) {
int i = n - 1;
int j = 0;
int num = 0;
while (i >= 0 && j < n) {
if (matrix[i][j] <= mid) {
num += i + 1;
j++;
} else {
i--;
}
}
return num >= k;
}
int kthSmallest(vector>& matrix, int k) {
int n = matrix.size();
int left = matrix[0][0];
int right = matrix[n - 1][n - 1];
while (left < right) {
int mid = left + ((right - left) >> 1);
if (check(matrix, mid, k, n)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
};
class Solution {
public:
void wiggleSort(vector& nums) {
if(nums.empty()) return ;
sort(nums.begin(),nums.end());
for(int i = 0;i
class Solution {
public:
int minimumTotal(vector>& triangle) {
int n = triangle.size();
vector> ans(n,vector(n));
ans[0][0] = triangle[0][0];
for(int i = 1;i
class Solution {
public:
vector largestDivisibleSubset(vector& nums) {
int n = nums.size();
sort(nums.begin(),nums.end());
vector dp(n,1);
int maxsize = 1;
int maxvalue = nums[0];
for(int i=1;i maxsize)
{
maxsize = dp[i];
maxvalue = nums[i];
}
}
vector ans;
if(maxsize == 1)
{
ans.push_back(nums[0]);
return ans;
}
for(int i=n-1;i>=0 && maxsize > 0;--i)
{
if(dp[i] == maxsize && maxvalue % nums[i] == 0)
{
ans.push_back(nums[i]);
maxvalue = nums[i];
maxsize--;
}
}
return ans;
}
};
class Solution {
public:
int trapRainWater(vector>& heightMap) {
int row = heightMap.size();
int col = heightMap[0].size();
int maxheight = 0;
//寻找三维矩阵中最高的高度
for(int i=0;i> water(row,vector(col,maxheight));
queue> q;
for(int i=0;iheightMap[i][j])
{
water[i][j] = heightMap[i][j];
q.push({i,j});
}
}
}
}
//从四周向内部收缩
while(!q.empty())
{
int x = q.front().first;
int y = q.front().second;
q.pop();
if(x-1 >= 0)//上
{
//如果上边格子接了雨水以后的高度比当前格子接了雨水的高度还要高,那么高出来的这部分雨水必然会流走,
if(water[x][y] < water[x-1][y] && water[x-1][y] > heightMap[x-1][y])
{
water[x-1][y] = max(water[x][y],heightMap[x-1][y]);
q.push({x-1,y});
}
}
if(x+1 < row)//下
{
if(water[x][y] < water[x+1][y] && water[x+1][y] > heightMap[x+1][y])
{
water[x+1][y] = max(water[x][y],heightMap[x+1][y]);
q.push({x+1,y});
}
}
if(y-1 >= 0)//左
{
if(water[x][y] < water[x][y-1] && water[x][y-1] > heightMap[x][y-1])
{
water[x][y-1] = max(water[x][y],heightMap[x][y-1]);
q.push({x,y-1});
}
}
if(y+1 < col)//右
{
if(water[x][y] < water[x][y+1] && water[x][y+1] > heightMap[x][y+1])
{
water[x][y+1] = max(water[x][y],heightMap[x][y+1]);
q.push({x,y+1});
}
}
}
int ans = 0;
for(int i=1;i|
class Solution {
public:
void dfs(vector>& board,int x,int y,int row,int col)
{
if(x<0 || x>=row || y<0 || y>=col || board[x][y] != 'O') return;
board[x][y] = 'P';//标记
dfs(board,x+1,y,row,col);
dfs(board,x-1,y,row,col);
dfs(board,x,y+1,row,col);
dfs(board,x,y-1,row,col);
}
void solve(vector>& board) {
int row = board.size();
if(row == 0) return ;
int col = board[0].size();
for(int i=0;i|
class Solution {
public:
int subarraySum(vector& nums, int k) {
unordered_map m;
int sum = 0;
int ans = 0;
m[0] = 1;
for(int i=0;i
class Solution {
public:
int minSwaps(string s) {
//iOdd 1在奇数位上的总个数,iEven 1在偶数位上的总个数
int iOdd = 0, iEven = 0, n = s.length();
for(int i = 0; i < n; ++i){
if(s[i] == '1'){
if(i % 2 == 0) iEven++;
else iOdd++;
}
}
int n1 = iEven+iOdd;//1总共出现的次数
int n0 = n-n1;//0总共出现的次数
int ans = -1;
if(n1 >= n0-1 && n1<= n0+1){
if(n0==n1)ans = min(iEven, iOdd);
else if(n1 == n0+1) ans = iOdd;
else ans = iEven;
}
return ans;
}
};
class Solution {
public:
int getMaxLen(vector& nums) {
int m = nums.size();
vector positive(m);
vector negative(m);
if(nums[0]>0) positive[0] = 1;
else if(nums[0]<0) negative[0] = 1;
int maxlen = positive[0];
for(int i=1;i0)
{
positive[i] = positive[i-1]+1;
negative[i] = (negative[i-1]>0?negative[i-1]+1:0);
}
else if(nums[i]<0)
{
positive[i] = (negative[i-1]>0?negative[i-1]+1:0);
negative[i] = positive[i-1]+1;
}
else{
positive[i] = 0;
negative[i] = 0;
}
maxlen = max(maxlen,positive[i]);
}
return maxlen;
}
};
class Solution {
public:
int longestSubsequence(vector& arr, int difference) {
if(arr.empty()) return 0;
unordered_map m;
int ans = INT_MIN;
for(auto& x:arr)
{
m[x] = m[x-difference]+1;
ans = max(ans,m[x]);
}
return ans;
}
};
class Solution {
public:
string lastSubstring(string s) {
if(s.empty()) return "";
int left = 0;
int right = 1;
int k = 0;//偏移,对于相同的字符,则更长的字典序更大,而我们通过移动偏移k来判断当前的两个字符是否相等。
int len = s.size();
while(right+k len2
//所以先判断s[left] < s[right+k]
//再判断s[left+k] < s[right+k]
else if(s[left+k] < s[right+k])
{
left = right;
right++;
k=0;
}
else{
right++;
k=0;
}
}
return s.substr(left);
}
};
class Solution {
public:
unordered_map m;
int dfs(TreeNode* root,int cur,int targetSum)
{
if(root == nullptr) return 0;
int ret = 0;
cur+=root->val;
if(m.count(cur-targetSum))
{
ret+=m[cur-targetSum];
}
m[cur]++;
ret+=dfs(root->left,cur,targetSum);
ret+=dfs(root->right,cur,targetSum);
m[cur]--;
return ret;
}
int pathSum(TreeNode* root, int targetSum) {
m[0] = 1;//前缀和为0的路径有1条
return dfs(root,0,targetSum);
}
};
这类题通常是指,判断一个数是否为x的幂(x=1,2,3....),对于这类型题,有一个通用的模板。
例如,下面的代码是判断一个数是否为4的幂(其他的也一样)
class Solution {
public:
bool isPowerOfFour(int n) {
if(n == 0) return false;
while(n%4==0)
{
n/=4;
}
return n == 1;
}
};
class Solution {
public:
int totalHammingDistance(vector& nums) {
int ans = 0;
int n = nums.size();
for(int i=0;i<32;++i)
{
int cur = 0;
for(auto& x:nums)
{
cur+=(x>>i)&1;//(x>>i)&1计算的是当前的第i位是否为1
}
ans+=cur*(n-cur);//某位上有c个1,每个1对应n - c个0,总贡献就是c * (n - c)
}
return ans;
}
};
/*class Solution {
public:
int missingNumber(vector& nums) {
int n = nums.size();
int sum = (n*(n+1))/2;//前n项求和公式,可能存在数据溢出问题
int res = 0;
for(auto x:nums)
{
res+=x;
}
return sum-res;
}
};*/
class Solution {
public:
int missingNumber(vector& nums) {
int ans = nums.size();
for(int i=0;i
class Solution {
public:
int numSubarrayProductLessThanK(vector& nums, int k) {
if(nums.empty() || k == 0 || k == 1) return 0;
int res = 1;
int ans = 0;
int left = 0;
for(int right = 0;right= k)
{
res/=nums[left++];
}
ans+=right-left+1;
/*为什么这里是right-left+1
比如现在有一个满足题意的子数组为{1,2,3,4},
那么{4} {3,4} {2,3,4} {1,2,3,4}也一定是满足题意的
所以其实就是这个子数组的元素个数,即长度
*/
}
return ans;
}
};
class Solution {
public:
TreeNode* head = new TreeNode();
TreeNode* pre = head;
TreeNode* increasingBST(TreeNode* root) {
func(root);
return head->right;
}
void func(TreeNode*root)
{
if(root != nullptr)
{
func(root->left);
pre->right = root;
pre = root;
root->left = nullptr;
func(root->right);
}
}
};
class Solution {
public:
vector> ans;
vector temp;
vector> allPathsSourceTarget(vector>& graph) {
if(graph.empty()) return {};
temp.push_back(0);//因为每一条路径一定是从0开始的,所以我们先将0放入temp中
dfs(graph,0);//开始深度优先遍历
return ans;
}
void dfs(vector> graph,int cur)
{
if(cur == graph.size()-1)//说明此时已经遍历到一条路径的终点了
{
ans.push_back(temp);
return;
}
for(auto& y:graph[cur])
{
temp.push_back(y);//接着从以y为出发点的路径开始遍历
dfs(graph,y);
temp.pop_back();//以y为出发点的路径完成遍历
}
}
};//深度优先遍历
class Solution {
public:
int minEatingSpeed(vector& piles, int h) {
int left = 1;
int right = 1000000000;
while(left<=right)
{
int mid = (right-left)/2+left;
if(Can(piles,mid,h))//如果以mid的速度可以吃完,则试着让狒狒吃的更慢一点
{
right = mid-1;
}
else
{
left = mid+1;
}
}
return left;
}
bool Can(vector& piles,int K,int h)
{
int sum = 0;//以K速度吃完这些香蕉,总共需要的时间
for(auto& x:piles)
{
sum+=x/K;
if(x%K)
{
sum+=1;
}
}
return sum<=h;
}
};
class Solution {
public:
int partition(vector& nums,int left,int right)
{
int temp = nums[left];//基准数->固定
int low = left;
while(left=temp)
{
--right;
}
while(left& nums, int k) {
int target = nums.size()-k;
int left = 0;
int right = nums.size()-1;
while(left& nums,int left,int right)
{
srand(time(0));
int index = rand()%(right-left+1)+left;
int temp = nums[index];//基准数->随机
swap(nums[left],nums[index]);//先把基准数换到最左边
while(left=temp)
{
--right;
}
nums[left] = nums[right];
while(left& nums, int k) {
int target = nums.size()-k;
int left = 0;
int right = nums.size()-1;
while(left
class Solution {
public:
int Find(vector& parent,int index)//返回index的根结点
{
while(parent[index] != index)
{
index = parent[index];
}
return index;
}
void Union(vector& parent,int x,int y)
{
int X = Find(parent,x);
int Y = Find(parent,y);
if(X != Y)//如果两个节点的根结点不同,说明他们两个不在同一个集合里,则可以进行合并
{
parent[X] = Y;
}
}
int findCircleNum(vector>& isConnected) {
int n = isConnected.size();
int m = isConnected[0].size();
vector parent(n+1);
for(int i=1;i<=n;++i)
{
parent[i] = i;
}
for(int i=0;i
class Solution {
public:
int Find(vector& parent,int index)
{
while(parent[index] != index)
{
index = parent[index];
}
return index;
}
void Union(vector& parent,int x,int y)
{
int X = Find(parent,x);
int Y = Find(parent,y);
if(X != Y)
{
parent[X] = Y;
}
}
bool connected(vector& parent,int x,int y)//判断x和y是否已在同一集合中
{
return Find(parent,x) == Find(parent,y);
}
vector findRedundantConnection(vector>& edges) {
int n = edges.size();
int m = edges[0].size();
vector parent(n+1);
for(int i=1;i<=n;++i)
{
parent[i] = i;
}
for(auto& edge:edges)
{
int x = edge[0];
int y = edge[1];
if(!connected(parent,x,y))
{
Union(parent,x,y);
}
else
{
return {x,y};
}
}
return {};
}
};
class Solution {
public:
vector> updateMatrix(vector>& mat) {
queue> q;
for(int i=0;i=0 && ny>=0 && nx
class Solution {
public:
int evalRPN(vector& tokens) {
if(tokens.empty()) return 0;
stack s;
for(auto& x:tokens)
{
if(isdigit(x[0]) || x[0] == '-' && x.size()>1)//当前为数字,数字分为正负,如果是-的话,要判断当前字符长度,不然可能和符号-混淆
{
s.push(stoi(x));//如果是数字,则push到栈中
}
else//如果是符号,则将栈中的前两个元素拿出来,计算完后,将结果再插入栈中
{
int a = s.top();
s.pop();
int b = s.top();
s.pop();
if(x=="+") s.push(a+b);
else if(x == "-") s.push(b-a);
else if(x == "*") s.push(a*b);
else s.push(b/a);
}
}
return s.top();
}
};
class Solution {
public:
unordered_map m;
int dfs(TreeNode* root,int cur,int targetSum)
{
if(root == nullptr) return 0;
int ret = 0;
cur+=root->val;
if(m.count(cur-targetSum))
{
ret+=m[cur-targetSum];
}
m[cur]++;
ret+=dfs(root->left,cur,targetSum);
ret+=dfs(root->right,cur,targetSum);
m[cur]--;
return ret;
}
int pathSum(TreeNode* root, int targetSum) {
m[0] = 1;//前缀和为0的路径有1条
return dfs(root,0,targetSum);
}
};
class Solution {
public:
string lastSubstring(string s) {
if(s.empty()) return "";
int left = 0;
int right = 1;
int k = 0;//偏移,对于相同的字符,则更长的字典序更大,而我们通过移动偏移k来判断当前的两个字符是否相等。
int len = s.size();
while(right+k len2
//所以先判断s[left] < s[right+k]
//再判断s[left+k] < s[right+k]
else if(s[left+k] < s[right+k])
{
left = right;
right++;
k=0;
}
else{
right++;
k=0;
}
}
return s.substr(left);
}
};
class Solution {
public:
int removeDuplicates(vector& nums) {
int n = nums.size();
if(n<=2) return n;
int slow = 2;
int fast = 2;
while(fast
class Solution {
public:
int beautySum(string s) {
if(s.empty()) return 0;
int sum = 0;
int len = s.size();
for(int i=0;i
class Solution {
public:
int getMaxLen(vector& nums) {
int m = nums.size();
vector positive(m);
vector negative(m);
if(nums[0]>0) positive[0] = 1;
else if(nums[0]<0) negative[0] = 1;
int maxlen = positive[0];
for(int i=1;i0)
{
positive[i] = positive[i-1]+1;
negative[i] = (negative[i-1]>0?negative[i-1]+1:0);
}
else if(nums[i]<0)
{
positive[i] = (negative[i-1]>0?negative[i-1]+1:0);
negative[i] = positive[i-1]+1;
}
else{
positive[i] = 0;
negative[i] = 0;
}
maxlen = max(maxlen,positive[i]);
}
return maxlen;
}
};
class Solution {
public:
bool isPerfectSquare(int num) {
if(num == 0) return false;
int left = 1;
int right = num;
while(left<=right)
{
int mid = ((right-left)>>1)+left;
if((long long)mid*mid>num) right = mid-1;
else left = mid+1;
}
return right*right == num;
}
};
class Solution {
public:
struct TrieNode
{
int index;
vector child;
TrieNode():child(26),index(-1){}
};
TrieNode* root = new TrieNode();
void Delete(TrieNode* node)
{
if(node == nullptr) return ;
for(int i=0;i<26;++i)
{
Delete(node->child[i]);
node->child[i] = nullptr;
}
delete node;
}
void insert(string word,int s)
{
TrieNode* cur = root;
for(auto& ch:word)
{
ch-='a';
if(cur->child[ch] == nullptr)
{
cur->child[ch] = new TrieNode();
}
cur = cur->child[ch];
}
cur->index = s;
}
void search(string word,vector>& ans,int s)
{
TrieNode* cur = root;
for(auto& ch:word)
{
ch-='a';
if(cur->index != -1)
{
ans[cur->index].push_back(s);
}
if(cur->child[ch] == nullptr) return;
cur = cur->child[ch];
}
if(cur->index != -1) ans[cur->index].push_back(s);
}
vector> multiSearch(string big, vector& smalls) {
int m = big.size();
int n = smalls.size();
vector> ans(n,vector{});
for(int i=0;i
class Solution {
private:
vector ans;
vector segments;
public:
void dfs(const string& s, int segId, int segStart) {
// 如果找到了 4 段 IP 地址并且遍历完了字符串,那么就是一种答案
if (segId == 4) {
if (segStart == s.size()) {
string ipAddr;
for (int i = 0; i < 4; ++i) {
ipAddr += to_string(segments[i]);
if (i != 3) {
ipAddr += ".";
}
}
ans.push_back(move(ipAddr));
}
return;
}
// 如果还没有找到 4 段 IP 地址就已经遍历完了字符串,那么提前回溯
if (segStart == s.size()) {
return;
}
// 由于不能有前导零,如果当前数字为 0,那么这一段 IP 地址只能为 0
if (s[segStart] == '0') {
segments[segId] = 0;
dfs(s, segId + 1, segStart + 1);
}
// 一般情况,枚举每一种可能性并递归
int addr = 0;
for (int segEnd = segStart; segEnd < s.size(); ++segEnd) {
addr = addr * 10 + (s[segEnd] - '0');
if (addr > 0 && addr <= 0xFF) {
segments[segId] = addr;
dfs(s, segId + 1, segEnd + 1);
} else {
break;
}
}
}
vector restoreIpAddresses(string s) {
segments.resize(4);
dfs(s, 0, 0);
return ans;
}
};
class Solution {
public:
int maxCount(int m, int n, vector>& ops) {
int mina = m;
int minb = n;
for(auto& x:ops)
{
mina = min(mina,x[0]);
minb = min(minb,x[1]);
}
return mina*minb;
}
};
class Solution {
public:
int translateNum(int num) {
string src = to_string(num);
int n = src.size();
vector dp(n+1);
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; ++i) {
auto pre = src.substr(i - 2, 2);
if (pre <= "25" && pre >= "10") {
dp[i] = dp[i-1]+dp[i-2];
}
else
{
dp[i] = dp[i-1];
}
}
return dp[n];
}
};
int func(int n, int m)
{
vector> dp(122,vector(122,0));
//dp[i][j]代表i个数(从1-i)和是j的组合数
dp[0][0] = 1;
for(int k=1;k<=m;++k)
dp[0][k] = 0;
for(int k=1;k<=n;++k)
dp[k][0] = 1;
for(int j=1;j<=m;++j)
for(int i=1;i<=n;++i)
if(j>=i)
dp[i][j] = dp[i-1][j] + dp[i-1][j-i];
else
dp[i][j] = dp[i-1][j];
return dp[n][m];
}
class Solution {
public:
bool validateStackSequences(vector& pushed, vector& popped) {
if(pushed.empty() || popped.empty()) return true;
stack s;
int index = 0;
for(auto& x:pushed)
{
s.push(x);
while(!s.empty() && s.top() == popped[index])
{
s.pop();
index++;
}
}
return s.empty();
}
};
class Solution {
public:
vector permutation(string s) {
vector res;
dfs(res,s,0);
return res;
}
void dfs(vector &res,string &s,int pos){
if(pos == s.size())
res.push_back(s);
for(int i=pos;i
class Solution {
public:
bool isStraight(vector& nums) {
if(nums.empty()) return false;
sort(nums.begin(),nums.end());
int temp = 0;
for(int i=1;i<5;++i)
{
if(nums[i-1] == 0) continue;
if(nums[i] == nums[i-1]) return false;
temp+=nums[i]-nums[i-1];
}
return temp<5;
}
};
class Solution {
public:
vector> findContinuousSequence(int target) {
vector> ans;
vector temp;
for(int left = 1,right = 2;left < right;)
{
int sum = (right-left+1)*(left+right)/2;
/*
等差数列求和公式:
Sn = n*a1+n(n-1)d/2
Sn = n(a1+an)/2;
此题中,n = (right-left+1) a1 = left an = right
*/
if(sum == target)
{
temp.clear();
for(int i=left;i<=right;++i)
{
temp.push_back(i);
}
ans.push_back(temp);
++left;
}
else if(sum < target) right++;
else left++;
}
return ans;
}
};
class Solution {
public:
int cuttingRope(int n) {
if(n == 2) return 1;
if(n == 3) return 2;
if(n == 4) return 4;
long ans = 1;
while(n>4)
{
ans*=3;
n-=3;
ans%=1000000007;
}
//循环结束后,绳子的长度还剩下n,此时n=1,2,3,4
return (ans*n)%1000000007;
}
};
class Solution {
public:
int getMoneyAmount(int n) {
vector> dp(n+1,vector(n+1));
for(int i=n-1;i>=1;--i)
{
for(int j=i+1;j<=n;++j)
{
int cur = INT_MAX;
for(int k=i;k
class Solution {
public:
int ans;
int reversePairs(vector& nums) {
ans = 0;
if(nums.empty()) return 0;
vector temp(nums.size());
MergeSort(nums,temp,0,nums.size()-1);
return ans;
}
void MergeSort(vector& nums,vector& temp,int left,int right)
{
if(left < right)
{
int mid = (right-left)/2+left;
MergeSort(nums,temp,left,mid);
MergeSort(nums,temp,mid+1,right);
Merge(nums,temp,left,right);
}
}
void Merge(vector& nums,vector& temp,int left,int right)
{
int mid = (right-left)/2+left;
int i = left;
int j = mid+1;
int index = 0;
while(i<=mid && j<=right)
{
if(nums[i] <= nums[j])
{
temp[index++] = nums[i++];
}
else
{
ans+=(mid-i+1);
temp[index++] = nums[j++];
}
}
while(i<=mid)
{
temp[index++] = nums[i++];
}
while(j<=right)
{
temp[index++] = nums[j++];
}
index = 0;
while(left<=right)
{
nums[left++] = temp[index++];
}
}
};
class Solution {
public:
vector constructArr(vector& a) {
int n = a.size();
vector ans(n);
int sum = 1;
for(int i=0;i=0;--i)
{
ans[i]*=sum;// 再乘右边的数(不包括自己)
sum*=a[i];
}
return ans;
}
};
class Solution {
public:
vector> findContinuousSequence(int target) {
vector> ans;
vector temp;
for(int left = 1,right = 2;left < right;)
{
int sum = (right-left+1)*(left+right)/2;
/*
等差数列求和公式:
Sn = n*a1+n(n-1)d/2
Sn = n(a1+an)/2;
此题中,n = (right-left+1) a1 = left an = right
*/
if(sum == target)
{
temp.clear();
for(int i=left;i<=right;++i)
{
temp.push_back(i);
}
ans.push_back(temp);
++left;
}
else if(sum < target) right++;
else left++;
}
return ans;
}
};
class Solution {
public:
bool isStraight(vector& nums) {
if(nums.empty()) return false;
sort(nums.begin(),nums.end());
int temp = 0;
for(int i=1;i<5;++i)
{
if(nums[i-1] == 0) continue;
if(nums[i] == nums[i-1]) return false;
temp+=nums[i]-nums[i-1];
}
return temp<5;
}
};
class Solution {
public:
vector permutation(string s) {
vector res;
dfs(res,s,0);
return res;
}
void dfs(vector &res,string &s,int pos){
if(pos == s.size())
res.push_back(s);
for(int i=pos;i
class Solution {
public:
bool validateStackSequences(vector& pushed, vector& popped) {
if(pushed.empty() || popped.empty()) return true;
stack s;
int index = 0;
for(auto& x:pushed)
{
s.push(x);
while(!s.empty() && s.top() == popped[index])
{
s.pop();
index++;
}
}
return s.empty();
}
};
class Solution {
public:
int maxCount(int m, int n, vector>& ops) {
int mina = m;
int minb = n;
for(auto& x:ops)
{
mina = min(mina,x[0]);
minb = min(minb,x[1]);
}
return mina*minb;
}
};
struct TrieNode {
int val;
TrieNode * next[26];
TrieNode() {
this->val = 0;
for (int i = 0; i < 26; ++i) {
this->next[i] = nullptr;
}
}
};
class MapSum {
public:
MapSum() {
this->root = new TrieNode();
}
void insert(string key, int val) {
int delta = val;
if (cnt.count(key)) {
delta -= cnt[key];
}
cnt[key] = val;
TrieNode * node = root;
for (auto c : key) {
if (node->next[c - 'a'] == nullptr) {
node->next[c - 'a'] = new TrieNode();
}
node = node->next[c - 'a'];
node->val += delta;
}
}
int sum(string prefix) {
TrieNode * node = root;
for (auto c : prefix) {
if (node->next[c - 'a'] == nullptr) {
return 0;
} else {
node = node->next[c - 'a'];
}
}
return node->val;
}
private:
TrieNode * root;
unordered_map cnt;
};
class MapSum {
public:
unordered_map m;
MapSum() {
}
void insert(string key, int val) {
m[key] = val;
}
int sum(string prefix) {
int ans = 0;
for(auto& it:m)
{
if(it.first.find(prefix) == 0)
{
ans+=it.second;
}
}
return ans;
}
};
/**
* Your MapSum object will be instantiated and called as such:
* MapSum* obj = new MapSum();
* obj->insert(key,val);
* int param_2 = obj->sum(prefix);
*/
class Solution {
public:
bool verifyPostorder(vector& postorder) {
return func(postorder,0,postorder.size()-1);
}
bool func(vector& postorder,int left,int right)
{
if(left >= right) return true;
int index = left;
while(postorder[index] < postorder[right] && index < right) ++index;
for(int i=index;i
class Solution {
public:
int peakIndexInMountainArray(vector& arr) {
int n = arr.size();
int left = 1;
int right = n-2;
while(left <= right)
{
int mid = (left+right)/2;
if(arr[mid] > arr[mid-1])
{
left = mid+1;
}
else
{
right = mid-1;
}
}
return right;
}
};
普通方法找最大值
class Solution {
public:
int peakIndexInMountainArray(vector& arr) {
int ans = 0;
int max = INT_MIN;
for(int i=0;i max)
{
max = arr[i];
ans = i;
}
}
return ans;
}
};
class Solution {
public:
int ans;
int findTilt(TreeNode* root) {
ans = 0;
dfs(root);
return ans;
}
int dfs(TreeNode* root)
{
if(root == nullptr) return 0;
int leftsum = dfs(root->left);
int rightsum = dfs(root->right);
ans+=abs(leftsum-rightsum);
return leftsum+rightsum+root->val;
}
};
class Solution {
public:
int numDecodings(string s) {
int n = s.size();
if(n == 0) return 0;
vector dp(n+1);
dp[0] = 1;
for(int i=1;i<=n;++i)
{
if(s[i-1] != '0')
{
dp[i]+=dp[i-1];
}
if(i>1 && s[i-2] != '0' && ((s[i-2]-'0')*10+(s[i-1]-'0') <= 26))
{
dp[i] += dp[i-2];
}
}
return dp[n];
}
};
class Solution {
public:
int minCostClimbingStairs(vector& cost) {
int n = cost.size();
vector dp(n+1);
dp[0] = 0;
dp[1] = 0;
for(int i=2;i<=n;++i)
{
dp[i] = min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
}
return dp[n];
}
};
class Solution {
public:
int integerBreak(int n) {
vector dp(n+1);
for(int i=2;i<=n;++i)
{
int cur = 0;
for(int j=1;j
class Solution {
public:
int eraseOverlapIntervals(vector>& intervals) {
if (intervals.empty()) {
return 0;
}
sort(intervals.begin(), intervals.end(), [](const auto& u, const auto& v) {
return u[0] < v[0];
});
int n = intervals.size();
vector f(n, 1);
for (int i = 1; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (intervals[j][1] <= intervals[i][0]) {
f[i] = max(f[i], f[j] + 1);
}
}
}
return n - *max_element(f.begin(), f.end());
}
};
class Solution {
public:
int eraseOverlapIntervals(vector>& intervals) {
int n = intervals.size();
if(n == 0) return 0;
sort(intervals.begin(),intervals.end(),[](const auto& a,const auto& b)
{
return a[1] < b[1];
});
int ans = 1;
int right = intervals[0][1];
for(int i=1;i= right)
{
ans++;
right = intervals[i][1];
}
}
return n-ans;
}
};
class Solution {
public:
int ans;
int findTargetSumWays(vector& nums, int target) {
ans = 0;
dfs(nums,target,0,0);
return ans;
}
void dfs(vector& nums,int target,int index,int sum)
{
if(index == nums.size())
{
if(sum == target)
{
ans++;
}
}
else{
dfs(nums,target,index+1,sum+nums[index]);
dfs(nums,target,index+1,sum-nums[index]);
}
}
};
class Solution {
public:
int longestMountain(vector& arr) {
int n = arr.size();
int ans = 0;
int left = 0;
while(left+2arr[right+1])
{
while(right+1 < n && arr[right] > arr[right+1])
{
++right;
}//此时right代表了当前这座山的右山脚
ans = max(ans,right-left+1);
}
else//arr[right] == arr[right+1];
{
++right;
}
}
left = right;
}
return ans;
}
};
class Solution {
public:
int wiggleMaxLength(vector& nums) {
int up = 1;
int down = 1;
int n = nums.size();
for(int i=1;inums[i-1])
{
up = down+1;
}
else if(nums[i] < nums[i-1])
{
down = up+1;
}
}
return n < 2?n:max(up,down);
}
};
class Solution {
public:
int ans;
int findTilt(TreeNode* root) {
ans = 0;
dfs(root);
return ans;
}
int dfs(TreeNode* root)
{
if(root == nullptr) return 0;
int leftsum = dfs(root->left);
int rightsum = dfs(root->right);
ans+=abs(leftsum-rightsum);
return leftsum+rightsum+root->val;
}
};
class Solution {
public:
TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
if(root == nullptr || p == nullptr) return nullptr;
if(root->val <= p->val)// 当前节点值小于等于目标值,那么当前目标值的后继者必然在右子树
{
return inorderSuccessor(root->right,p);
}
// 否则结果有可能是当前节点,或者在当前节点的左子树中
// 那么先去左子树找一下试试,找不到的话返回当前节点即是结果
TreeNode* ans = inorderSuccessor(root->left,p);
return ans == nullptr?root:ans;
}
};
class Solution {
public:
bool isUnique(string astr) {
if(astr.empty()) return true;
int mask = 0;
for(auto& ch:astr)
{
int temp = ch-'a';
if(mask & (1<
class Solution {
public:
int maxProduct(vector& words) {
int len = words.size();
vector mask(len);
for(int i=0;i
class Solution {
public:
int findLHS(vector& nums) {
sort(nums.begin(),nums.end());
int begin = 0;
int ans = 0;
for(int end = 0;end1)
{
++begin;
}
if(nums[end]-nums[begin] == 1)
{
ans = max(ans,end-begin+1);
}
}
return ans;
}
};
class Solution {
public:
int waysToChange(int n) {
int coins[] = {1, 5, 10, 25};
vector dp(n+1);
dp[0] = 1;
for(int &coin : coins){
for(int i = coin; i <= n; i++){
dp[i] = (dp[i] + dp[i - coin]) % 1000000007;
}
}
return dp[n];
}
};
这要从最大子序和说起,由简到繁 - 最大子矩阵 - 力扣(LeetCode) (leetcode-cn.com)
class Solution {
public:
vector getMaxMatrix(vector>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
int max = matrix[0][0];
vector ans(4);
vector> presum(m+1,vector(n));
for(int i=1;i<=m;++i)
{
for(int j = 0;j arr(n);
for(int i=0;i0)
{
sum+=arr[i];
}
else
{
sum = arr[i];
start =i;
}
if(sum>max)
{
max = sum;
ans[0] = top;
ans[1] = start;
ans[2] = end;
ans[3] = i;
}
}
}
}
return ans;
}
};
class Solution {
public:
vector> ans;
vector> pathWithObstacles(vector>& obstacleGrid)
{
if(obstacleGrid.empty() || obstacleGrid[0][0] == 1 ||obstacleGrid.back().back() == 1)
{
return {};
}
vector> visited(obstacleGrid.size(),vector(obstacleGrid[0].size(),false));
ans.push_back({0,0});
if(dfs(obstacleGrid,visited,0,0))
{
return ans;
}
return {};
}
bool dfs(vector>& obstacleGrid,vector>& visited,int i,int j)
{
if(i == obstacleGrid.size()-1 && j == obstacleGrid[0].size()-1)
{
return true;
}
if(j+1
class Solution {
public:
unordered_set hset;
// 单词组里面的某个单词可以由另外的两个单词组合而成
string longestWord(vector& words) {
sort(words.begin(), words.end(), [](string &a, string &b){
if(a.size() == b.size()) return a <= b;//如果长度相同则按字典序排
else return a.size() > b.size();//否则按长度降序排列
});
vector ans;
for(auto w:words) hset.insert(w);//先把所有单词放到hash里
for(auto w:words) {
hset.erase(w);
if(Check(w)) return w;
hset.insert(w);
}
return "";
}
bool Check(string word) {
if(hset.count(word)) return true;//说明单词word在words中不止一个
// 长度
for(int i = 1; i < word.size(); i++) {
string left = word.substr(0, i);
string right = word.substr(i, word.size() - left.size());
if(hset.count(left) && Check(right)) return true;
}
return false;
}
};
class Solution {
public:
vector findSwapValues(vector& array1, vector& array2) {
int sum1 = 0;
int sum2 = 0;
for(int x:array1)
{
sum1+=x;
}
for(int x:array2)
{
sum2+=x;
}
int dif = sum1-sum2;
if((dif & 1) == 1)//如果是奇数
{
return {};
}
dif/=2;
unordered_set s(array2.begin(),array2.end());
for(int x:array1)
{
if(s.count(x-dif))
{
return {x,x-dif};
}
}
return {};
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int ans = 0;
int pathSum(TreeNode* root, int sum) {
if(root == nullptr)
{
return 0;
}
dfs(root,sum);
pathSum(root->left,sum);
pathSum(root->right,sum);
return ans;
}
void dfs(TreeNode* root,int sum)
{
if(root == nullptr)
{
return;
}
sum-=root->val;
if(sum == 0)
{
ans++;
}
dfs(root->left,sum);
dfs(root->right,sum);
}
};
class Solution {
public:
int smallestDifference(vector& a, vector& b) {
int m=a.size(),n=b.size();
sort(a.begin(),a.end());
sort(b.begin(),b.end());
long res=INT_MAX;
int i=0,j=0;
while(i
class Solution {
public:
int respace(vector& dictionary, string sentence) {
int sz = sentence.size();
vector dp(sz + 1, 0); dp[0] = 0;
for (int i = 1; i <= sz; i++) {
dp[i] = dp[i - 1] + 1;
for (auto& p : dictionary) {
int pz = p.size();
if (i >= p.size()) {
string substr = sentence.substr(i - pz, pz);
if (substr == p) dp[i] = min(dp[i], dp[i - pz]);
else dp[i] = min(dp[i], dp[i - pz] + pz);
}
}
}
return dp[sz];
}
};
class Solution {
public:
int closedIsland(vector>& grid) {
int m = grid.size();
int n = grid[0].size();
for(int i = 0;i>& grid,int i,int j)
{
if(i<0 || j<0 || i>=grid.size() || j>=grid[0].size() || grid[i][j] == 1)
{
return;
}
grid[i][j] = 1;
dfs(grid,i+1,j);
dfs(grid,i-1,j);
dfs(grid,i,j+1);
dfs(grid,i,j-1);
}
};
什么情况下grid2
中的一个岛屿B
是grid1
中的一个岛屿A
的子岛?
当岛屿B
中所有陆地在岛屿A
中也是陆地的时候,岛屿B
是岛屿A
的子岛。
反过来说,如果岛屿B
中存在一片陆地,在岛屿A
的对应位置是海水,那么岛屿B
就不是岛屿A
的子岛。
那么,我们只要遍历grid2
中的所有岛屿,把那些不可能是子岛的岛屿排除掉,剩下的就是子岛。
class Solution {
public:
int countSubIslands(vector>& grid1, vector>& grid2) {
int m = grid1.size();
int n = grid1[0].size();
for(int i=0;i>& grid,int i,int j)
{
if(i<0 || j<0 || i>=grid.size() || j>=grid[0].size() || grid[i][j] == 0)
{
return ;
}
grid[i][j] = 0;
dfs(grid,i+1,j);
dfs(grid,i-1,j);
dfs(grid,i,j+1);
dfs(grid,i,j-1);
}
};
计算出总的岛屿数量,因为有一对相邻两个陆地,边的总数就减2,那么在计算出相邻岛屿的数量就可以了。
class Solution {
public:
int islandPerimeter(vector>& grid) {
int sum = 0; // 陆地数量
int cover = 0; // 相邻数量
for (int i = 0; i < grid.size(); i++) {
for (int j = 0; j < grid[0].size(); j++) {
if (grid[i][j] == 1) {
sum++;
// 统计上边相邻陆地
if(i - 1 >= 0 && grid[i - 1][j] == 1) cover++;
// 统计左边相邻陆地
if(j - 1 >= 0 && grid[i][j - 1] == 1) cover++;
// 为什么没统计下边和右边? 因为避免重复计算
//因为我们遍历的方式是从上到下,从左到右进行的
}
}
}
return sum * 4 - cover * 2;
}
};
比如题目输入下面这个二维矩阵:
其中有四个岛屿,但是左下角和右上角的岛屿形状相同,所以不同的岛屿共有三个,算法返回 3。
很显然我们得想办法把二维矩阵中的「岛屿」进行转化,变成比如字符串这样的类型,然后利用 HashSet 这样的数据结构去重,最终得到不同的岛屿的个数。
如果想把岛屿转化成字符串,说白了就是序列化,序列化说白了遍历嘛。
首先,对于形状相同的岛屿,如果从同一起点出发,dfs
函数遍历的顺序肯定是一样的。
所以,遍历顺序从某种意义上说就可以用来描述岛屿的形状,比如下图这两个岛屿:
假设它们的遍历顺序是:
下,右,上,撤销上,撤销右,撤销下
如果我用分别用1, 2, 3, 4
代表上下左右,用-1, -2, -3, -4
代表上下左右的撤销,那么可以这样表示它们的遍历顺序:
2, 4, 1, -1, -4, -2
你看,这就相当于是岛屿序列化的结果,只要每次使用dfs
遍历岛屿的时候生成这串数字进行比较,就可以计算到底有多少个不同的岛屿了。
要想生成这段数字,需要稍微改造dfs
函数,添加一些函数参数以便记录遍历顺序:
void dfs(int[][] grid, int i, int j, StringBuilder sb, int dir) {
int m = grid.length, n = grid[0].length;
if (i < 0 || j < 0 || i >= m || j >= n
|| grid[i][j] == 0) {
return;
}
// 前序遍历位置:进入 (i, j)
grid[i][j] = 0;
sb.append(dir).append(',');
dfs(grid, i - 1, j, sb, 1); // 上
dfs(grid, i + 1, j, sb, 2); // 下
dfs(grid, i, j - 1, sb, 3); // 左
dfs(grid, i, j + 1, sb, 4); // 右
// 后序遍历位置:离开 (i, j)
sb.append(-dir).append(',');
}
dir
记录方向,dfs
函数递归结束后,sb
记录着整个遍历顺序,其实这就是回溯算法框架,你看到头来这些算法都是相通的。
有了这个dfs
函数就好办了,我们可以直接写出最后的解法代码:
int numDistinctIslands(int[][] grid) {
int m = grid.length, n = grid[0].length;
// 记录所有岛屿的序列化结果
HashSet islands = new HashSet<>();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 1) {
// 淹掉这个岛屿,同时存储岛屿的序列化结果
StringBuilder sb = new StringBuilder();
// 初始的方向可以随便写,不影响正确性
dfs(grid, i, j, sb, 666);
islands.add(sb.toString());
}
}
}
// 不相同的岛屿数量
return islands.size();
}
这道题目一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼。
先确定右边评分大于左边的情况(也就是从前向后遍历)
此时局部最优:只要右边评分比左边大,右边的孩子就多一个糖果,全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果
局部最优可以推出全局最优。
如果ratings[i] > ratings[i - 1] 那么[i]的糖 一定要比[i - 1]的糖多一个,所以贪心:candyVec[i] = candyVec[i - 1] + 1
再确定左孩子大于右孩子的情况(从后向前遍历)
遍历顺序这里有同学可能会有疑问,为什么不能从前向后遍历呢?
因为如果从前向后遍历,根据 ratings[i + 1] 来确定 ratings[i] 对应的糖果,那么每次都不能利用上前一次的比较结果了。
所以确定左孩子大于右孩子的情况一定要从后向前遍历!
如果 ratings[i] > ratings[i + 1],此时candyVec[i](第i个小孩的糖果数量)就有两个选择了,一个是candyVec[i + 1] + 1(从右边这个加1得到的糖果数量),一个是candyVec[i](之前比较右孩子大于左孩子得到的糖果数量)。
那么又要贪心了,局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量即大于左边的也大于右边的。全局最优:相邻的孩子中,评分高的孩子获得更多的糖果。
局部最优可以推出全局最优。
所以就取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,candyVec[i]只有取最大的才能既保持对左边candyVec[i - 1]的糖果多,也比右边candyVec[i + 1]的糖果多。
class Solution {
public:
int candy(vector& ratings) {
vector candyVec(ratings.size(), 1);
// 从前向后
for (int i = 1; i < ratings.size(); i++) {
if (ratings[i] > ratings[i - 1]) candyVec[i] = candyVec[i - 1] + 1;
}
// 从后向前
for (int i = ratings.size() - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1] ) {
candyVec[i] = max(candyVec[i], candyVec[i + 1] + 1);
}
}
// 统计结果
int result = 0;
for (int x:candyVec) result += x;
return result;
}
};
class Solution {
public:
void solveSudoku(vector>& board) {
if(!board.empty())
{
backtrack(board,0,0);
}
}
bool backtrack(vector>& board, int i, int j)
{
int m = 9, n = 9;
if (j == n) {
// 穷举到最后一列的话就换到下一行重新开始。
return backtrack(board, i + 1, 0);
}
if (i == m) {
// 找到一个可行解,触发 base case
return true;
}
if (board[i][j] != '.') {
// 如果有预设数字,不用我们穷举
return backtrack(board, i, j + 1);
}
for (char ch = '1'; ch <= '9'; ch++) {
// 如果遇到不合法的数字,就跳过
if (!isValid(board, i, j, ch))
continue;
board[i][j] = ch;
// 如果找到一个可行解,立即结束
if (backtrack(board, i, j + 1)) {
return true;
}
board[i][j] = '.';
}
// 穷举完 1~9,依然没有找到可行解,此路不通
return false;
}
bool isValid(vector>&board, int r, int c, char n)
{
for (int i = 0; i < 9; i++) {
// 判断行是否存在重复
if (board[r][i] == n) return false;
// 判断列是否存在重复
if (board[i][c] == n) return false;
// 判断 3 x 3 方框是否存在重复
if (board[(r/3)*3 + i/3][(c/3)*3 + i%3] == n)
return false;
}
return true;
}
};
本质上在考察数学中的 进制 问题
换底公式:
class Solution {
public:
int poorPigs(int buckets, int minutesToDie, int minutesToTest) {
int base = minutesToTest / minutesToDie + 1;
int ans = ceil(log(buckets) / log(base));//log2 buckets / log2 base = log base buckets
return ans;
}
};
class Solution {
public:
//滑动窗口
vector findAnagrams(string s, string p) {
if(s.size() < p.size()) return {};
vector cnt_s(26);
vector cnt_p(26);
vector ans;
int left = 0;//滑动窗口左边界
int right = -1;//滑动窗口右边界
for(char& ch:p)
{
cnt_p[ch-'a']++;
cnt_s[s[++right]-'a']++;
}
if(cnt_p == cnt_s)
{
ans.emplace_back(left);
}
while(right < s.size()-1)
{
cnt_s[s[++right]-'a']++;//滑动窗口右边界右移,对应的新的右边界的字符个数加一
cnt_s[s[left++]-'a']--;//滑动窗口左边界右移,对应的之前的左边界的字符个数减一
if(cnt_s == cnt_p)//如果现在两个串的字符个数相等,则当前子串符合条件
{
ans.emplace_back(left);
}
}
return ans;
}
/*
在方法一的基础上,我们不再分别统计滑动窗口和字符串 p 中每种字母的数量,而是统计滑动窗口和字符串p 中 每种字母数量的差;并引入变量 differ 来记录当前窗口与字符串 pp 中数量不同的字母的个数,并在滑动窗口的过程中维护它。
在判断滑动窗口中每种字母的数量与字符串 p 中每种字母的数量是否相同时,只需要判断 differ 是否为p的长度即可。
*/
vector findAnagrams_(string s, string p) {
int m = s.size();
int n = p.size();
if(m cnt(26);
vector ans;
for(char& ch:p)
{
cnt[ch-'a']++;
}
int left = 0;
int right = 0;
while(right0)
{
cnt[s[right++]-'a']--;
if(right - left == n) ans.emplace_back(left);//判断differ
}
else{
cnt[s[left++]-'a']++;
}
}
return ans;
}
};