class Solution {
public:
int findGCD(vector<int>& nums) {
int min_num = *min_element(nums.begin(), nums.end());
int max_num = *max_element(nums.begin(), nums.end());
return gcd(min_num, max_num);
}
};
//gcd()函数的用法是包含头文件#include <numeric>
int gcd(int a, int b){
return b == 0 ? a : gcd(b, a%b);
}
/**
* 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:
int gcd(int a,int b){
return b == 0 ? a : gcd(b, a%b);
}
ListNode* insertGreatestCommonDivisors(ListNode* head) {
if(head == nullptr || head->next == nullptr){
return head;
}
ListNode*p1 = head;
ListNode*p2 = head->next;
while(p2){
int val = gcd(p1->val, p2->val);
ListNode* newNode = new ListNode(val, p2);
p1->next = newNode;
p1 = p2;
p2 = p2->next;
}
return head;
}
};
贪心+数学
对于数组中的每个元素,如果它与前面的元素最大公约数为1,那么它需要作为新的子数组的第一个元素。否则,它可以与前面的元素放在同一个子数组中。
因此,我们先初始化一个变量g,表示当前子数组的最大公约数。初始时,g为0,答案变量ans=1。
从前向后遍历数组,维护当前子数组的最大公约数g。如果当前元素x与g的最大公约数为1,那么我们需要将当前元素作为一个新的子数组的第一个元素。
class Solution{
public:
int minimumSplits(vector<int>& nums){
int ans = 1, g = 0;
for(int num: nums){
g = gcd(g, num);
if(g == 1){
++ans;
g = num;
}
}
return ans;
}
};
求最大公约数通用公式
int gcd(int a, int b){
return b == 0 ? a : gcd(b, a%b);
}
查看Linux磁盘用量常用命令
df -h
du -h
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
int ret = 0;
unordered_set<int> num_set;
for(int num : nums){
num_set.insert(num);
}
for(int num : nums){
//前一个没有
if(!num_set.count(num-1)){
int currentNum = num;
int len = 1;
while(num_set.count(currentNum + 1)){
currentNum++;
len++;
}
ret = max(ret, len);
}
}
return ret;
}
};
哈希表
枚举数组中的每个数x,考虑以x为起点,不断匹配x+1,x+2,…是否存在,假设最长匹配到x+y,那么长度为y+1.
枚举超时
前缀和+哈希表优化
定义pre[i]为[0…i]里所有数的和,则pre[i]由pre[i-1]递推而来
pre[i] = pre[i-1] + nums[i]
那么[j…i]这个子数组和为k可以转换为
pre[i] - pre[j-1] == k
移动一下
pre[j-1] = pre[i] - k
所以考虑以i结尾的和为k的连续子数组个数只需要统计有多少个前缀和pre[i] - k的pre[j]即可。
class Solution{
int subarraySum(vector<int>& nums, int k){
unordered_map<int, int>mp;
mp[0] = 1; //和为0的情况出现了一次
int count = 0, pre = 0;
for(auto&x : nums){
pre += x;
if(mp.find(pre-k) != mp.end()){
count += mp[pre-k];
}
mp[pre]++;
}
return count;
}
}
前缀和是指第一个元素到当前元素的所有元素之和,哈希表用于存储前缀和出现次数。
count记录和为k的连续子数组的个数。
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
//转置
for(int i=0; i<n; i++){
for(int j=i+1; j<n; j++){
swap(matrix[i][j], matrix[j][i]);
}
}
//两列交换 0 2 --- 0 3 1 2
int midJ = n/2;
for(int j=0; j<midJ; j++){
for(int i=0; i<n; i++){
swap(matrix[i][j], matrix[i][n-j-1]);
}
}
}
};
暴力
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size(), n = matrix[0].size();
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
if(matrix[i][j] == target){
return true;
}
}
}
return false;
}
};
z字形查找
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size(), n = matrix[0].size();
int x = 0, y = n-1;
while(x < m && y >= 0){
if(matrix[x][y] == target){
return true;
}
else if(matrix[x][y] > target){
y--;
}
else if(matrix[x][y] < target){
x++;
}
}
return false;
}
};
/**
* 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* reverseList(ListNode* head) {
if(head == nullptr || head->next == nullptr){
return head;
}
ListNode* pre = nullptr;
ListNode* cur = head;
while(cur){
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
};
给一个整数数组nums和一个整数k,统计并返回数组中和为k的子数组的个数。
前缀和+哈希表优化
定义pre[i]为[0,…,i]里所有数的和,则pre[i] = pre[i-1] + nums[i]
[j…,i]子数组和为k可以转换为pre[i] - pre[j-1] == k
转换为pre[j-1] = pre[i] - k
所以我们考虑以i结尾的和为k的连续子数组的个数时,只需要统计有多少个前缀和为pre[i] - k的pre[j]即可。
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int> mp; //<pre, count>
mp[0] = 1;
int count = 0, pre = 0;
for(int num : nums){
pre += num;
if(mp.count(pre - k)){
count += mp[pre-k];
}
mp[pre]++;
}
return count;
}
};
/**
* 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:
bool isPalindrome(ListNode* head) {
vector<int> nums;
while(head){
nums.push_back(head->val);
head = head->next;
}
int left = 0, right = nums.size() - 1;
while(left < right){
if(nums[left] != nums[right]){
return false;
}
left++;
right--;
}
return true;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head == nullptr || head->next == nullptr){
return false;
}
ListNode* slow = head;
ListNode* fast = head->next;
while(fast){
if(slow == fast){
return true;
}`在这里插入代码片`
if(fast->next != nullptr){
fast = fast->next->next;
}else{
fast = nullptr;
}
slow = slow->next;
}
return false;
}
};
二叉树的最大深度是指从根节点到最远叶子节点的最长路径上的节点数。
/**
* 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:
int maxDepth(TreeNode* root) {
if(root == nullptr){
return 0;
}
int lDepth = maxDepth(root->left);
int rDepth = maxDepth(root->right);
return max(lDepth, rDepth)+1;
}
};