jianzhioffer

1.二维数组
二分法

int m = arr.size();
int n = arr[0].size();

int r = 0, c = n-1; //右上角
while(r<m && c>=0)
//在左下角之前
if(target > arr[r][c]){
    ++r;//当前小了,往下找
}
else{
    --c;//当前大了,往左找
}

2.替换空格
Java

{
if(s == null || "".equals(s))
    return s;
return s.replaceAll(" ","REPLACE");
}

正常

O(N)
O(N)

string newstr='';
for(int i=0;i<str.length();i++)
{
    if(s[i] != ' ') newstr += str[i];
    else newstr += '%20';
}
return newstr;

O(N)
O(1) 用的原来的str,只是用常数个零食变量
双指针
漫漫云天字翱翔 已收藏

//先找到所有的空格
if(str[i] == ' ') spaceCount++;
//所有的空格换成%20
totalLen = length + spaceCount*2
//可以从后往前找
//j是延长后的str的指针
for(int i = length-1, j = totalLen - 1; j>i; j--, i--)
{
    if(str[i] != ' ') str[j] = str[i];
    else{
    str[j]='0';
    str[j-1]='2';
    str[j-2]='%';
    j-=2;
    }
}
return s;
  1. 反向打印链表
    后序遍历
if(!root) return;
dfs(root->left);
dfs(root->right);

链表的递归反向

vector<int> ret;
if(!head) return ret;
ret = printfromTailtoHead(head->next);
ret.push_back(head->val);
return ret;

4.(重要)重建二叉树
二叉树
前序:根左右
中序:左根右
后序:左右根

TreeNode* reconstructBT(vector<int> pre, vector<int> vin){
    if(pre.size()==0||vin.size()==0) return NULL;
    vector<int> PRE_LEFT, PRE_RIGHT, VIN_LEFT, VIN_RIGHT;
    TreeNode* ret = new TreeNode(pre[0]);
    //找vin中根节点所在的位置存在gen中
    int gen=0;
    for(int i=0;i<vin.size();i++){
        if(vin[i]==pre[0]){
        gen = i;
        break;//找到根节点在中序遍历中的位置
        }
    }
    //对中序遍历,根节点在左右子树中间
    //左子树
    for(int i=0;i<gen;i++){
        VIN_LEFT.push_back(vin[i]);
        PRE_LEFT.push_back(pre[i+1]);//先序遍历第一个是根节点,之后先是所有的左子树
    }
    //右子树
    for(int i =gen+1;i<vin.size();i++){//从gen+1开始
        VIN_RIGHT.push_back(vin[i]);
        PRE_RIGHT.push_back(pre[i]);
    }
    //递归建树
    ret->left = reconstructBT(PRE_LEFT, VIN_LEFT);
    ret->right = reconstructBT(PRE_RIGHT, VIN_RIGHT);
    return ret;
}

5.(简单经典)用两个栈实现队列

stack<int> s1;//保存用
stack<int> s2;//辅助用

push正常push
pop分情况
int pop(){
    //情况1:不止一个元素,需要用s2的辅助栈
    while(s1.size() != 1){
        s2.push(s1.top());
        s1.pop();//stack是FILO,我们要FIFO,这里不是return,只是找到first in
    }
    int value = s1.top();//FI element
    s1.pop();//FI要pop
    //情况2:把辅助栈里的元素放回数据栈
    while(!s2.empty()){
        s1.push(s2.top());
        s2.pop();
    }
    return value;
}
  1. 旋转数组的最小数字
    int minArray(vector<int>& numbers) {
        //二分查找
        int low=0;
        int high=numbers.size()-1;
        while(low<high)
        {
            int mid = low + (high-low)/2;
            if(numbers[mid]<numbers[high]){
                high = mid;//我们在找最小值
            }
            else if(numbers[mid]>numbers[high]){
                low = mid+1;//前面的肯定是递增,都比high高只能往后找
            }
            else{
                high -= 1;
            }
        }
        return numbers[low];//找的最小值
    }

7.(入门经典)
递归很慢

int Fib(int n){
    if(n==0) return 0;
    if(n==1||n==2) return 1;
    return Fib(n-1)+Fib(n-2);
}

很简单的好解法

int Fib(int n){
    if(n==0) return 0;
    if(n==1||n==2) return 1;
    int first=0,second=1,third=1;
    for(int i=2;i<=n;++i){
        third=first+second;
       first=second;
       second=third;
    }
    return third;
}

更好

    int fib(int n) {
        int a=0,b=1,c=0;//注意于fib的区别
        for(int i=0;i<n;++i){
            a=b,b=c;
            c=(a+b)%1000000007;
        }
        return c;//注意于fib的区别
    }

8(经典简单)青蛙跳台阶
*和Fib其实一样

  1. 递归,太慢
int jump(int n){
    if(n==1) return 1;
    if(n==2) return 2;
    return jump(n-1)+jump(n-2);
    //有n级台阶的跳法等于n-1和n-2两种情况的综合
}
  1. Fib
int Fib(int n){
    if(n<=2) return n;
    int first=1,second=2,third=0;
    for(int i=3;i<=n;++i){
       third=first+second;
       first=second;
       second=third;
    }
    return third;
}

更好

    int numWays(int n) {
        int a=0,b=1,c=1;//注意于fib的区别
        for(int i=0;i<n;++i){
            a=b,b=c;
            c=(a+b)%1000000007;
        }
        return b;//注意于fib的区别
    }

9 复杂的跳台阶
n级台阶,
第一步有n种可能
第二步可能是f(n) = f(n-1)+f(n-2)+…+f(1)
同理,f(n-1) = f(n-2)+f(n-3)+…+f(1)
所以,f(n) = 2f(n-1)
从这里可得,每次都是
2
已知f(1)=1;f(2)=2;
2^(n-1)
return pow(2,n-1)

10 矩阵覆盖
依然是Fib的变种
n个21的小矩形覆盖一个2n的大矩形
已知f(1)=1;f(2)=2;
f(n) = f(n-1) + f(n-2)
因为一条
hen着覆盖,2n就变成2(n-1)
shu着,变成2*(n-2)//因为是2*n,占掉两格另外一边也固定了

11 32位二进制中1的个数
思路:一个不为零的数-1后,二进制原来最右边的1->0,其后所有0变为1,1保持不变。
–>把一个整数-1,在和原来做and运算,会把整数最右的一个1变成0
–>可以重复多少次,就有几个1

int ret=0;
while(n!=0){
    n=n&(n-1);
    ret++;
}
return ret;

用CPP的bit set

bitset<32> bit(n);
return bit.count();
  1. (再看)double的int次方
    快速幂
    x^n
double myPow(double x, int n){
    double res=1;
    double base=x;
    if(n<0){
        n = -(++n);//abs(INT_MIN)>INT_MAX,先自增1
    }
    while(n>0){
        if(n&1) res*=x;
        n=n>>1;
        x*=x;
    }
    return n<0?1/(res*base):res;//这里补上了自增的1
}

13 奇数跳到偶数前
1.直接遍历两边,一次奇数一次偶数
2.头尾双指针
O(N)
O(N)
遍历一遍

int res[arr.size];
head=idx_head=0;
tail=idx_tail=arr.size()-1;
while(head<arr.size() && tail >=0){
    if(arr[head]%2==1){
        res[idx_head]=arr[head];
        idx_head++;
    }
    head++;//head只处理奇数
    if(arr[tail%2==0]){
    
    
}
  1. 链表中的倒数第k节点
    双指针
slow = head;
while(k!=0){
    k--;
    if(head != nullptr) head = head->next;
    else
       return nullptr;
}
//head先走k步
while(head != nullptr){
    slow = slow->next;
    head = head->next;
}
return slow;
  1. 反转链表
    3指针
//初始化
pre = nullptr;
cur = head;
next = nullptr;
while(cur){
   next = cur->next;//保存
   cur->next = pre;//反转
   pre = cur;//更新头节点
   cur = next;//移向下一个
}
return pre;

16.合并两个排序的列表
一般创建单列表都会设一个虚拟头节点(哨兵)

if(head1 == nullptr) return head2;
if(head2 == nullptr) return head1;
ListNode* vhead = new ListNode(-1);
ListNode* cur = vhead;
while(head1 && head2){
    if(head1->val <= head2->val){
        cur->next=head1;
        head1=head1->next;
    }
    else{
        cur->next=head2;
        head2=head2->next;
    }
    cur=cur->next;
}
cur->next = (head1 !=nullptr ? head1:head2);
return vhead->next;

TODO: 递归版本

  1. 树的子结构(再看下)
    树的题目,大多数都用递归
    tree1中是否含有tree2
bool core(root1, root2){
    if(root2 == nullptr) return true;
    if(root1 == nullptr) return false;
    if(root1->val == root2->val){
        //根一样,再判断左右子树
        return core(root1->left,root2->left) && core(root1->right,root2->right)
    }
    return false;
}

bool hasSubtree(root1,root2){
    if(root1==nullptr||root2==nullptr) return false;
    return hasSubtree(root1->left,root2)||hasSubtree(root1->right,root2)||core(root1,root2);
}
  1. 二叉树的镜像
    有很多东西,可复习
void Mirror(TreeNode* proot){
    if(proot == nullptr) return;
    swap(proot->left,proot->right);
    Mirror(proot->left);
    Mirror(proot->right);
}
  1. 顺时针打印矩阵
    再看,很考验思路
vector<int> spiralOrder(vector<vector<int>>& matrix){
    if(matrix.size() == 0 || matrix.size() ==0) return vector<int> ();
    int left = 0, right = matrix[0].size() - 1, top = 0, bottom = matrix.size() - 1;
    while(left<=right && top<=bottom){
        for(int i=left;i<=right;++i){
           //cout<<matrix[top][i]<<" ";
           result.push_back(matrix[top][i]);
        }
        if(++top>bottom) break;//top == bottom;
        for(int i=top;i<=bottom;++i){
            //cout<<matrix[i][right]<<" ";
            result.push_back(matrix[i][right]);
        }
        if (--right<left) break;//避免left=right
        for (int i=right;i>=left;--i){
            //cout << matrix[bottom][i]<< " ";
            result.push_back(matrix[bottom][i]);
        }
        if(--bottom<top) break;
        for(int i=right;i>=left;--i){
            //cout << matrix[i][left]<< " ";
            result.push_back(matrix[i][left]);
        }
        if(++left > right) break;  
    }
    return result;
}
  1. stack实现min函数
    时间复杂度O(1)
    空间复杂度O(n),开辟一个辅助栈
    正常情况下返回最小值需要遍历整个stack
    时间复杂度O(n)

双栈法:普通栈normal,辅助栈minval

stack<int> normal, minval;
void push(int val){
    normal.push(val);
    if(minval.empty()){
        minval.push(val);
    }
    else{
        minval.push(std::min(val,minval.top()));//一定要有std
    }
}

void pop(){
    normal.pop();
    minval.pop();
}

int top(){
    return normal.top();
}

int min(){
    return minval.top();
}
  1. stack
    复习
    辅助栈
int len = pushV.size();
int popIndex=0;
stack<int> st;
for(int i=0;i<len;++i){
    st.push(pushV[i]);
    while(popIndex<len && !st.empty() && st.top() == popV[popIndex]){
        st.pop();
        popIndex++;//该位pop没问题
    }
    return st.empty();//如果辅助栈中能全pop出去,即可能
}
  1. 二叉树
queue<TreeNode*> q;
q.push(root);
TreeNode* temp;
vector<int> result;
while(!q.empty()){
    temp = q.front();
    q.pop();
    result.push_back(temp->val);
    if(temp->left) q.push(node->left);
    if(node->right) q.push(node->right);
}
return result;
  1. (未看)使用后序遍历
    递归解决树的问题
  1. (未看)二叉树路径和

  2. 双头链表
    (可复习)

 if (head == nullptr) return nullptr;
        unordered_map<Node*, Node*> unmp;
        for (Node* p = head; p != nullptr;p=p->next)
        {
            unmp[p] = new Node(p->val);
        }
        for (Node* p = head; p != nullptr; p = p->next)
        {
            unmp[p]->next = unmp[p->next];//这里要注意是 unmp[p->next] 千万注意,好好想想
            unmp[p]->random = unmp[p->random];//下同
        }

        return unmp[head];

26 二叉搜索树与双向链表(未看)

27 字符串的排列(未看)

28 数组中出现次数超过一半的数字
很简单的unordered map,可以自己试一下

int MoreThanHalfNum_Solution(vector<int> numbers) {

    unordered_map<int, int>unmp;
    int len = numbers.size();
    for (int i = 0; i < len; ++i) {
        unmp[numbers[i]]++;
        if (unmp[numbers[i]] > len / 2) return numbers[i];
    }
    return 0;
    }
  1. 最小的k个数
    pivot是数组中第pos-l+1小的数
    类似快排的思路,可以再复习下!
    https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/submissions/

  2. 连续子数组的最大和
    简单,可以再看看
    分治:O(nlogn)
    O(logn)
    动态规划:O(n)
    O(1)
    状态定义:
    dp[i]
    转移方程:
    dp[i-1]>0 --> dp[i]=dp[i-1]+nums[i]
    dp[i-1]<=0 --> dp[i] = nums[i]//dp[i-1]+nums[i]比nums[i]小
    初始状态:dp[0]=nums[0]
    返回值:dp列表中的最大值

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int pre=0, res=nums[0];
        for(auto &x: nums){
            pre = max(pre+x,x);
            res = max(res,pre);
        }
        return res;
    }
};

31 整数1出现的系数
略过

if(n<10) return 1;
int high=n, pow=1;
while(high>=10){
    high=high/10;
    pow=pow*10;
}
int last = n-high*pow;

32 数组排成最小的数
略过


33 丑数
x(n+1) = min(xa2,xb3,xc*5)
动态规划
完成

34 只出现一次的字符
用unordered map做,挺简单的
完成

35 数组中的逆排序
跳过

36 链表的第一个公共节点
简单且重要!
双指针
O(m+n)
O(1)
已解决

37 数字出现的次数
方法一:二分查找
经典!!!

直观的思路肯定是从前往后遍历一遍。用两个变量记录第一次和最后一次遇见 \textit{target}target 的下标,但这个方法的时间复杂度为 O(n)O(n),没有利用到数组升序排列的条件。

由于数组已经排序,因此整个数组是单调递增的,我们可以利用二分法来加速查找的过程。

考虑 \textit{target}target 在数组中出现的次数,其实我们要找的就是数组中「第一个等于 \textit{target}target 的位置」(记为 \textit{leftIdx}leftIdx)和「第一个大于 \textit{target}target 的位置减一」(记为 \textit{rightIdx}rightIdx)。当 \textit{target}target 在数组中存在时,\textit{target}target 在数组中出现的次数为 \textit{rightIdx}-\textit{leftIdx}+1rightIdx−leftIdx+1。

二分查找中,寻找 \textit{leftIdx}leftIdx 即为在数组中寻找第一个大于等于 \textit{target}target 的下标,寻找 \textit{rightIdx}rightIdx 即为在数组中寻找第一个大于 \textit{target}target 的下标,然后将下标减一。两者的判断条件不同,为了代码的复用,我们定义 binarySearch(nums, target, lower) 表示在 \textit{nums}nums 数组中二分查找 \textit{target}target 的位置,如果 \textit{lower}lower 为 \rm truetrue,则查找第一个大于等于 \textit{target}target 的下标,否则查找第一个大于 \textit{target}target 的下标。

最后,因为 \textit{target}target 可能不存在数组中,因此我们需要重新校验我们得到的两个下标 \textit{leftIdx}leftIdx 和 \textit{rightIdx}rightIdx,看是否符合条件,如果符合条件就返回 \textit{rightIdx}-\textit{leftIdx}+1rightIdx−leftIdx+1,不符合就返回 00

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/solution/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-wl6kr/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

二分查找的时间复杂度为 O(logn),一共会执行两次,因此总时间复杂度为 O(logn)。

int L(int *nums, int x, int size)
{
    int l=0, r=size-1, mid=0;
    while( l < r ) {
        mid = l + (r-l)/2;
        if( nums[mid] >= x ) r = mid;
        else l = mid + 1;
    }
    return nums[l] == x?l:0;
}

int R(int *nums, int x, int size)
{
    int l=0, r=size-1, mid=0;
    while( l < r ) {
        mid = l + (r-l)/2 + 1;
        if( nums[mid] <= x ) l = mid;
        else r = mid - 1;
    }
    return nums[l] == x?l:-1;
}

int search(int* nums, int numsSize, int target){
    if( !numsSize ) return 0;
    return R(nums,target,numsSize) - L(nums,target,numsSize) + 1;
}

38 二叉树的深度
简单,重要的递归

 int maxDepth(TreeNode* root) {
        if(root==nullptr) return 0;
        int leftdepth = maxDepth(root->left);
        int rightdepth = maxDepth(root->right);
        return 1+ max(leftdepth,rightdepth)

    }
int height(TreeNode* root) {
        if (root == NULL) {
            return 0;
        } else {
            return max(height(root->left), height(root->right)) + 1;
        }
    }

39 平衡二叉树

    int height(TreeNode* root) {
        if (root == NULL) {
            return 0;
        } else {
            return max(height(root->left), height(root->right)) + 1;
        }
    }

    bool isBalanced(TreeNode* root) {
        if (root == NULL) {
            return true;
        } else {
            return abs(height(root->left) - height(root->right)) <= 1 && isBalanced(root->left) && isBalanced(root->right);
        }
    }

40 掠过

41 和为S的整数序列
掠过
42 和为S的两个数字
简单

    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> result;
        if(nums.size()==0) return result;
        int low=0,high=nums.size()-1;
        while(low<=high){
            if(nums[low]+nums[high]==target){
                result.push_back(nums[low]);
                result.push_back(nums[high]);
                return result;
            }
            else if(nums[low]+nums[high]<target) low++;
            else high--;
        }
        return result;
    }

43 左旋转字符串

    string reverseLeftWords(string s, int n) {
        int len=s.size();
        if(len==0) return s;
        if(n>=len) n=n%len;//n超过了str的长度
        string temp=s+s;
        string result;
        result.resize(len);
        for(int i=n,idx=0;i<len+n;i++,idx++){
            result[idx] = temp[i];
        }
        return result;
    }
  1. 反转单词序列
    掠过

45 扑克牌顺子
简单
重要

    bool isStraight(vector<int>& nums) {
        int minIndex = 0;
        sort(nums.begin(), nums.end());
        for(int i = 0; i < nums.size()-1; i++)
        {
            if(nums[i] == 0)    ++minIndex;   
            else if(nums[i] == nums[i+1])    return false;   //除开为0的情况,存在重复时
        }
        return nums[4] - nums[minIndex] <= 4;
    }
  1. 圆圈中剩下的数
    int lastRemaining(int n, int m) {
        if(n==1) return 0;
        else{
            return (lastRemaining(n-1,m)+m)%n;
        }
    }

47

48 不使用加号使用加法

while(num2!=0){
    int sum=num1^num2;//异或
    int carry=(num1&num2)<<1;
    num1=sum;
    num2=carry;
}
return num1;

49 跳过

  1. 数组中重复的数字
    int findRepeatNumber(vector<int>& nums) {
        unordered_map<int, bool> map;
        for(int num : nums) {
            if(map[num]) return num;
            map[num] = true;
        }
        return -1;
    }

51 二叉搜索树公共祖先节点

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        vector<TreeNode*> path_p=getPath(root,p);
        vector<TreeNode*> path_q=getPath(root,q);
        TreeNode* ancestor;
        for(int i=0;i<path_p.size()&&i<path_q.size();++i){
            if(path_p[i]==path_q[i]){
                ancestor = path_p[i];
            }
            else{
                break;
            }
        }
        return ancestor;
    }

    vector<TreeNode*> getPath(TreeNode* root, TreeNode* target){
        vector<TreeNode*> path;
        TreeNode* node = root;
        while(node != target){
            path.push_back(node);
            if(target->val<node->val){
                node=node->left;
            }
            else{
                node=node->right;
            }
        }
        path.push_back(node);
        return path;
    }

52(68)二叉树的公共节点
*没太看懂

TreeNode* ans;
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        dfs(root,p,q);
        return ans;

        
    }
    
    bool dfs(TreeNode* root, TreeNode* p, TreeNode* q){
        if(root==nullptr) return false;
        bool lson = dfs(root->left,p,q);
        bool rson = dfs(root->right,p,q);
        if(lson&&rson||((root->val ==p->val||root->val ==q->val)&&(lson||rson))){
            ans = root;
            //1. lson&&rson说明左子树和右子树都包含p或者q,一个p,一个q
            //2. root正好是p或q节点,检查左或右子树是否至少有一个包含p或q
            //这两种情况,我们就找到了最近公共祖先
            //递归是从底(叶子)向上的,所以所有满足条件的一定是深度最大的
        }
        return lson||rson||(root->val ==p->val||root->val ==q->val);
    }//返回的是root是否包含p或q节点

July28

33
再看下
34

public:
    vector<vector<int>> ret;
    vector<int> path;
    void dfs(TreeNode* root, int target){
        if(root==nullptr) return;
        path.push_back(root->val);
        target -= root->val;
        if(root->left==nullptr&&root->right==nullptr&&target==0){
            ret.push_back(path);
            dfs(root->left,target);
            dfs(root->right,target);
            path.pop_back();//重要
        }
        
    }
    vector<vector<int>> pathSum(TreeNode* root, int target) {
        dfs(root,target);
        return ret;    
    }
};
//DFS
//O(N^2) 上半部分链状,下半部分完全二叉树
//O(N)
Node* copyRandomList(Node* head) {
        if(head==nullptr) return nullptr;
        Node* cur=head;
        unordered_map<Node*, Node*> map;
        //创建新节点
        while(cur!=nullptr){
            map[cur] =new Node(cur->val);
            cur = cur->next;
        }
        cur = head;
        //构建新链表的指向
        while(cur!=nullptr){
            map[cur]->next = map[cur->next];//重要
            map[cur]->random = map[cur->random];//重要
            cur = cur->next;
        }
        //返回
        return map[head];
    }

再看,要再复习!!没看懂

    Node* pre=nullptr, *head=nullptr;
    Node* treeToDoublyList(Node* root) {
        if(!root) return root;
        dfs(root);
        head->left=pre;
        pre->right=head;
        return head;
        
    }
    void dfs(Node* cur){
        if(cur==nullptr) return;
        dfs(cur->left);
        if(pre!=nullptr) pre->right=cur;
        else head=cur;//保留链表头节点
        cur->left=pre;
        pre=cur;
        dfs(cur->right);
    }

再看,没看懂
Offer 44. 数字序列中某一位的数字

    int findNthDigit(int n) {
        int digit=1;//记录位数
        long start=1;//记录某一位数开始的第一个数
        long count=digit*start*9;//记录某一位数包含的所有数字个数

        //判断第n位数字是几位数
        while(n>count){
            n-=count;
            digit+=1;
            start*=10;
            count=digit*start*9;
        }

        //判断第n位数字是几位数
        long number = start + (n-1)/digit;

        //判断第n位数字在第二步中找出的数是第几位
        string s_number = to_string(number);
        return s_number[(n-1)%digit] - '0';

    }

完全没看懂…
再看

class Solution {
public:
    string minNumber(vector<int>& nums) {
        vector<string> strs;
        for(int i=0;i<nums.size();i++){
            strs.push_back(to_string(nums[i]));
        }
        quickSort(strs,0,strs.size()-1);
        string res;
        for(string s: strs){
            res.append(s);
        }
        return res;
    }

    void quickSort(vector<string>& strs, int l, int r){
        if(l>=r) return;
        int i=l,j=r;
        while(i<j){
            while(strs[j]+strs[l]>=strs[l]+strs[j]&& i<j) j--;
            while(strs[i]+strs[l]<=strs[l]+strs[i]&& i<j) i++;
            swap(strs[i],strs[j]);
        }
        swap(strs[i],strs[l]);
        quickSort(strs,l,i-1);
        quickSort(strs,i+1,r);
    }

};

//快排平均O(nlogn),最差O(N2)
//O(N)

再看,复习下

    int translateNum(int num) {
        //动态规划转移方程
        //f(i)=f(i-1)+f(i-2)
        //边界条件f(-1)=0, f(0)=1
        //O(n) O(1):滚动数组(常见的空间优化)
        string src = to_string(num);
        int a=0, b=0, c=1;
        for(int i=0;i<src.size();++i){
            a=b;
            b=c;
            c=0;
            c = b+c;
            if(i==0) continue;
            auto pre=src.substr(i-1,2);
            if(pre<="25"&&pre>="10"){
                c = c+a;
            }
        }
        return c;
    }

47 礼物
动态规划,再看

int maxValue(vector<vector<int>>& grid) {
        int m=grid.size();
        int n=grid[0].size();
        //定义动态规划的存储
        vector<vector<int>>dp(m,vector<int>(n,0));
        dp[0][0]=grid[0][0];
        //初始化动态规划的临界条件
        for(int i=1;i<n;i++){
            dp[0][i]=dp[0][i-1]+grid[0][i];
        }  
        for(int j=1;j<m;j++){
            dp[j][0]=dp[j-1][0]+grid[j][0];
        }   
        //确定动态规划的转移方程
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                dp[i][j]=max(dp[i][j-1],dp[i-1][j])+grid[i][j];
            }
        }
        //返回答案
        return dp[m-1][n-1];
    }

34 路径

class Solution {
public:
    vector<vector<int>> ret;
    vector<int> path;

    void dfs(TreeNode* root, int target) {
        if (root == nullptr) {
            return;
        }
        path.emplace_back(root->val);
        target -= root->val;
        if (root->left == nullptr && root->right == nullptr && target == 0) {
            ret.emplace_back(path);
        }
        dfs(root->left, target);
        dfs(root->right, target);
        path.pop_back();
    }

    vector<vector<int>> pathSum(TreeNode* root, int target) {
        dfs(root, target);
        return ret;
    }
};

48最长不重复

64

int sumNums(int n) {
        n && (n += sumNums(n-1));
        return n;
    }

66

    vector<int> constructArr(vector<int>& a) {
        int len = a.size();
        if(len == 0) return {};
        vector<int> b(len,1);
        b[0] = 1;
        int tmp = 1;
        for(int i = 1; i < len; i++){
            b[i] = b[i-1] * a[i-1];
        }
        for(int i = len - 2; i>=0; i--){
            tmp *= a[i+1];
            b[i] *= tmp;
        }
        return b;
    }
    int strToInt(string str) {
        int i=0, sign=1;
        long res=0;//直接用long暂时解决越界的问题
        while(str[i]==' ') i++;
        if(str[i] == '-') sign = -1;
        if(str[i] == '-'||str[i] == '+') i++;
        for(;i<str.size();i++){
            if(str[i]>'9'||str[i]<'0') break;
            res = res*10 + (str[i]-'0');//转换
            if(res>=INT_MAX&&sign==1) return INT_MAX;
            if(res>INT_MAX&&sign==-1) return INT_MIN;
        }
        return sign*res;
      }

12
没太看懂

    bool exist(vector<vector<char>>& board, string word) {
        for(int i=0;i<board.size();i++){
            for(int j=0;j<board[0].size();j++){
                if(dfs(board,word,i,j,0))
                    return true;
            }
        }
        return false;
    }
    
    bool dfs(vector<vector<char>>& b, string& w, int i, int j, int k){
        if(i>=b.size()||i<0||j>=b[0].size()||j<0||b[i][j]!=w[k])
            return false;
        if(k == w.length()-1)
            return true;
        char temp = b[i][j];
        b[i][j] = '/'; //该元素已访问过
        bool res = dfs(b,w,i+1,j,k+1) ||
                   dfs(b,w,i-1,j,k+1) ||
                   dfs(b,w,i,j+1,k+1) ||
                   dfs(b,w,i,j-1,k+1);
        b[i][j] = temp;
        return res;
    }

13 没看懂

    int count = 0;
    int movingCount(int m, int n, int k) {
        if(k==0) return 1;
        vector<vector<int>> visited(m, vector<int>(n));
        dfs(visited,0,0,m,n,k);
        return count;
    }
    
    void dfs(vector<vector<int>>& visited, int x, int y, int& m, int &n, int k){
        if (x>=m||x<0||y>=n||y<0||(x/10+x%10+y/10+y%10)>k||visited[x][y]==1)
            return;
        ++count;
        visited[x][y] = 1;
        int dx[4] = {-1,0,1,0}, dy[4]={0,1,0,-1};
        for(int q = 0; q < 4; ++q){
            int i = x + dx[q], j = y + dy[q];
            dfs(visited,i,j,m,n,k);
        }
    }

二刷
4 二维数组的查找
从右上到左下找

7 重建二叉树

TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    if(preorder.size()==0||inorder.size()==0) return NULL;
    vector<int> preorder_LEFT, preorder_RIGHT, inorder_LEFT, inorder_RIGHT;
    TreeNode* ret = new TreeNode(preorder[0]);
    //找inorder中根节点所在的位置存在gen中
    int gen=0;
    for(int i=0;i<inorder.size();i++){
        if(inorder[i]==preorder[0]){
        gen = i;
        break;//找到根节点在中序遍历中的位置
        }
    }
    //对中序遍历,根节点在左右子树中间
    //左子树
    for(int i=0;i<gen;i++){
        inorder_LEFT.push_back(inorder[i]);
        preorder_LEFT.push_back(preorder[i+1]);//先序遍历第一个是根节点,之后先是所有的左子树
    }
    //右子树
    for(int i =gen+1;i<inorder.size();i++){//从gen+1开始
        inorder_RIGHT.push_back(inorder[i]);
        preorder_RIGHT.push_back(preorder[i]);
    }
    //递归建树
    ret->left = buildTree(preorder_LEFT, inorder_LEFT);
    ret->right = buildTree(preorder_RIGHT, inorder_RIGHT);
    return ret;

    }

12 矩阵中的路径
dfs+剪枝
如果已访问过,
如果b[i][j]!=w[k] return FALSE

    bool exist(vector<vector<char>>& board, string word) {
        for(int i=0;i<board.size();i++){
            for(int j=0;j<board[0].size();j++){
                if(dfs(board,word,i,j,0))
                    return true;
            }
        }
        return false;
    }
    //k 是用来判断word中的index,从0开始

    bool dfs(vector<vector<char>>& b, string& w, int i, int j, int k){
        if(i>=b.size()||i<0||i>=b.size()||j<0||j>=b[0].size()||b[i][j]!=w[k])
            return false;
        if(k == w.length()-1)
            return true;
        char temp = b[i][j];
        b[i][j] = '/'; //该元素已访问过
        //k每次+1,从上下左右寻找
        bool res = dfs(b,w,i+1,j,k+1) ||
                   dfs(b,w,i-1,j,k+1) ||
                   dfs(b,w,i,j+1,k+1) ||
                   dfs(b,w,i,j-1,k+1);
        b[i][j] = temp;//当次遍历结束,要还原
        return res;
    }

13 机器人
dfs
和12类似

    int count = 0;//共用变量,记录可能的格子
    int movingCount(int m, int n, int k) {
        if(k==0) return 1;
        vector<vector<int>> visited(m, vector<int>(n));//m*n的矩阵
        dfs(visited,0,0,m,n,k);//从0,0开始
        return count;
    }
    //k是输入,所有数位要求之和
    void dfs(vector<vector<int>>& visited, int x, int y, int& m, int &n, int k){
        if (x>=m||x<0||y>=n||y<0||(x/10+x%10+y/10+y%10)>k||visited[x][y]==1)
            return;
        count++;
        visited[x][y] = 1;
        // int dx[4] = {-1,0,1,0}, dy[4]={0,1,0,-1};
        // for(int q = 0; q < 4; ++q){
        //     int i = x + dx[q], j = y + dy[q];
        //     dfs(visited,i,j,m,n,k);
        // }
        dfs(visited,x+1,y,m,n,k);
        dfs(visited,x-1,y,m,n,k);
        dfs(visited,x,y+1,m,n,k);
        dfs(visited,x,y-1,m,n,k);
    }

14
cutting rope
dynamic programming

  1. dp[i] 长度为i的身子剪短后的最大乘积
  2. dp[i] = max(dp[i], max(j*(i-j)),jdp[i-j])
    //当前长度,只剪成2段,j和(i-j),或者j
    dp[i-j]
  3. dp[2] = 1
        vector<int> dp(n+1,0);
        dp[1] = 1;
        dp[2] = 1;
        for(int i=3;i<=n;i++){
            for(int j=2;j<=i;j++){
                dp[i] = max(dp[i],max(j*(i-j), j*dp[i-j]));
            }
        }
        return dp[n];
/*
    int cuttingRope(int n) {
        //dp = max(result[i], result[j]*result[i-j])
        
        if(n <= 1) return 0;
        if(n == 2) return 1;
        if(n == 3) return 2;

        vector<int> result(n+1, 0);

        result[0] = 0;
        result[1] = 1;
        result[2] = 2;
        result[3] = 3;

        for(int i=4;i<=n;i++){
            for(int j=1;j<=i/2;j++){
                result[i]=max(result[j]* result[i-j], result[i]);
            }
        }
        return result[n];
    }
*/

大数求余问题
贪心算法

尽可能分为长度为3的小段时乘积最大

    int cuttingRope(int n) {
        if(n==2) return 1;
        if(n==3) return 2;
        int b = n%3, p=1000000007;//b是余数,最后要乘的
        long ret = 1;
        int lineNums = n/3;//可以截成3的数量
        for(int i=1;i<lineNums;i++)
            ret = 3*ret % p;//一直乘3,由于从i=1开始,少乘了一次
        if(b == 0)
            return (int)(ret * 3 % p);//被3整除算前一段
        if(b == 1)
            return (int)(ret * 4 % p);//被3整数余1,算前一段可以是2*2=4
        return (int)(ret * 6 % p);//被3整除余2,算前一段最大可以是2*3=6
    }

26 二叉树的子结构

    bool isSubStructure(TreeNode* A, TreeNode* B) {
        //dfs先序遍历
        if(A==nullptr||B==nullptr) return false;
        bool ret = false;
        if(A->val == B->val) ret = hasSubtree(A,B);
        if(!ret){
            ret = isSubStructure(A->left,B) || isSubStructure(A->right,B);
        }
        return ret;
    }
        
    //     //bfs层序遍历
    //     bool ret = false;
    //     if(A==nullptr||B==nullptr){
    //         return ret;
    //     }

    //     queue<TreeNode*> q;
    //     q.push(A);
    //     while(!q.empty()){
    //         int size = q.size();
    //         for(int i=0;i<size;i++){
    //             TreeNode* temp = q.front();
    //             q.pop();
    //             if(temp->val == B->val){
    //                 ret = hasSubtree(temp, B);//头是一样的时用这个比较
    //                 if(ret) return ret;
    //             }
    //             if (temp->left != nullptr)
    //                 q.push(temp->left);
    //             if (temp->right != nullptr)
    //                 q.push(temp->right);
    //         }
    //     }
    //     return ret;
    // }


    bool hasSubtree(TreeNode* A, TreeNode* B){
        if(B == nullptr) return true;
        if(A == nullptr || A->val != B->val) return false;
        return hasSubtree(A->left,B->left) &&  hasSubtree(A->right,B->right);
    }

32

class Solution {
public:
    vector<int> levelOrder(TreeNode* root) {
        vector<int> res;
        if(!root) return res;
        queue<TreeNode*> q;
        q.push(root);
        while(q.size()){
            TreeNode* node=q.front();
            q.pop();
            res.push_back(node->val);
            if(node->left) q.push(node->left);
            if(node->right) q.push(node->right);
        }
        return res;
    }
};
//从上到下,广度优先搜素
//BFS
//O(N),O(N),平衡二叉树,N/2个节点在queue中
//用queue实现层级遍历
   vector<vector<int>> levelOrder(TreeNode* root) {
        if(!root) return {};
        vector<vector<int>> ret;
        vector<int> temp;
        queue<TreeNode*> Q;
        Q.push(root);
        while(Q.size()){
            int size=Q.size();
            for(int i=0;i<size;++i){
                TreeNode* node=Q.front();
                temp.push_back(node->val);
                Q.pop();
                if(node->left) Q.push(node->left);
                if(node->right) Q.push(node->right);
            }
            ret.push_back(temp);
            temp.clear();//要清空
        }
        return ret;
    }
    vector<vector<int>> levelOrder(TreeNode* root) {
        if(!root) return {};
        vector<vector<int>> ret;
        
        queue<TreeNode*> Q;
        Q.push(root);
        while(Q.size()){
            vector<int> temp;
            int size=Q.size();
            for(int i=0;i<size;i++){
                TreeNode* node=Q.front();
                Q.pop();
                temp.push_back(node->val);
                if(node->left) Q.push(node->left);
                if(node->right) Q.push(node->right);
            }
            if(ret.size()%2==1) reverse(temp.begin(),temp.end());
            //奇数行要反转
            ret.push_back(temp);
        }
        return ret;
    }

33
二叉树的后序遍历

    bool verifyPostorder(vector<int>& postorder) {
        return recur(postorder,0,postorder.size()-1);
    }
    bool recur(vector<int>& postorder, int start, int end){
        if(start>=end) return true;
        int p = start;
        //二叉搜索树: 右 > 根 > 左
        //后序遍历:左右根
        while(p<end && postorder[p]<postorder[end]) p++;//找到右子树的第一个
        if(p == end) return recur(postorder,start,end-1);
        //没有右子树,只需要验证左子树
        int right1 = p;
        while(p<end && postorder[p]>postorder[end]) p++;//检查右子树是否全部比根大
        if(p<end) return false;
        return recur(postorder,start,right1-1) &&
                recur(postorder,right1,end-1);
    }

34 二叉树和为target的路径

class Solution {
public:
    vector<vector<int>> ret;
    vector<int> path;

    void dfs(TreeNode* root, int target) {
        if (root == nullptr) {
            return;
        }
        path.push_back(root->val);
        target -= root->val;
        if (root->left == nullptr && root->right == nullptr && target == 0) {
            ret.push_back(path);
        }
        dfs(root->left, target);
        dfs(root->right, target);
        path.pop_back();//remove the last element of a path to see other possibilities
    }

    vector<vector<int>> pathSum(TreeNode* root, int target) {
        dfs(root, target);
        return ret;
    }
};
//DFS
//O(N^2) 上半部分链状,下半部分完全二叉树
//O(N)

35 复杂链表的复制
已看
O(N)
O(N)

    Node* copyRandomList(Node* head) {
        if(head==nullptr) return nullptr;
        Node* cur=head;
        unordered_map<Node*, Node*> map;
        //创建新节点
        while(cur!=nullptr){
            map[cur] =new Node(cur->val);
            cur = cur->next;
        }
        cur = head;
        //构建新链表的指向
        while(cur!=nullptr){
            map[cur]->next = map[cur->next];//重要
            map[cur]->random = map[cur->random];//重要
            cur = cur->next;
        }
        //返回
        return map[head];
    }

36 二叉搜索树和双向链表
dfs
再看
中序遍历是增序

Node* pre=nullptr, *head=nullptr;
    Node* treeToDoublyList(Node* root) {
        if(root==nullptr) return root;
        dfs(root);
        head->left=pre;
        pre->right=head;
        return head;
        
    }
    void dfs(Node* cur){
        if(cur==nullptr) return;
        dfs(cur->left);
        if(pre!=nullptr) pre->right=cur;
        else head=cur;//保留链表头节点
        cur->left=pre;
        pre=cur;
        dfs(cur->right);
    }
  1. 再看, dfs
public:
    vector<string> permutation(string s) {
        string cur = "";
        vector<bool> used(s.size(),false);
        dfs(s,cur,used);

        for(auto& element: st) ret.push_back(element);
        return ret;
    }
    set<string> st;
    vector<string> ret;

    void dfs(string& s, string& cur, vector<bool>& used){
        if(cur.size() == s.size()){
            st.insert(cur);
            return;
        }
        for(int i=0;i<s.size();i++){
            if(used[i]) continue;
            cur = cur + s[i];
            used[i] = true;
            dfs(s,cur,used);
            used[i]=false;
            cur.pop_back();
        }
    }

38 string
再看下,回溯算法

    vector<string> ret;
    vector<bool> visited;

    void backtrack(const string& s, int i, int n, string& perm) {
        //i是当前的char数
        //n是perm中需要的char数,这里为3
        if (i == n) {
            ret.push_back(perm);
            return;
        }
        for (int j = 0; j < n; j++) {
            if (visited[j] || (j > 0 && !visited[j - 1] && s[j - 1] == s[j])) {
                continue;//以上三种情况不行
                //上一位已用过,两位一样
            }
            visited[j] = true;
            perm.push_back(s[j]);
            backtrack(s, i + 1, n, perm);//下一位
            perm.pop_back();//回溯算法的核心
            visited[j] = false;//这位处理好了
        }
    }

    vector<string> permutation(string s) {
        int n = s.size();
        visited.resize(n);
        sort(s.begin(), s.end());
        string perm;
        backtrack(s, 0, n, perm);
        return ret;
    }

44
在复习下

    int findNthDigit(int n) {
        int digit=1;//记录位数
        long start=1;//记录某一位数开始的第一个数
        long count=digit*start*9;//记录某一位数包含的所有数字个数

        //判断第n位数字是几位数
        while(n>count){
            n=n-count;//减去上一位所有的数字
            digit=digit+1;
            start=start*10;
            count=digit*start*9;
        }

        //判断第n位数字是几位数
        long number = start + (n-1)/digit;

        //判断第n位数字在第二步中找出的数是第几位
        string s_number = to_string(number);
        return s_number[(n-1)%digit] - '0';//这里返回的是int型

    }

45
排序,可以再复习下

    string minNumber(vector<int>& nums) {
        vector<string> strs;
        for(int i=0;i<nums.size();i++){
            strs.push_back(to_string(nums[i]));
        }
        quickSort(strs,0,strs.size()-1);//右边是size-1
        string res;
        for(string s: strs){
            res.append(s);
        }
        return res;
    }

    void quickSort(vector<string>& strs, int l, int r){
        if(l>=r) return;
        int i=l,j=r;
        while(i<j){
            //这里的+是字符串的拼接
            //x+y>y+x => x>y
            //x+y<y+x => x<y
            while(strs[j]+strs[l]>=strs[l]+strs[j]&& i<j) j--;
            while(strs[i]+strs[l]<=strs[l]+strs[i]&& i<j) i++;
            //x<y在这里的意义是应该在左边
            //上面两个while会一直将右边‘小’的和左边‘大’的交换
            swap(strs[i],strs[j]);
        }
        swap(strs[i],strs[l]);
        quickSort(strs,l,i-1);//左边
        quickSort(strs,i+1,r);//右边
    }

};

//快排平均O(nlogn),最差O(N2)
//O(N)

46
dp
滚动数组
在学习下

int translateNum(int num) {
        //动态规划转移方程(不同规模问题的联系)
        //两种可能性
        //1. 如果i和i-1个数字不能一起翻译,即不在10到25之间
        //dp[i]=dp[i-1]
        //2. 如果可以一起翻译
        //dp[i]=dp[i-1]+dp[i-2]
        //!!!两种可能性是或的关系
        //总的方法数取dp[i]=dp[i-1]+dp[i-2]
        //边界条件f(-1)=0, f(0)=1
        //O(n) O(1):滚动数组(常见的空间优化)
        string src = to_string(num);
        int a=0, b=0, c=1;
        for(int i=0;i<src.size();i++){
            a=b;
            b=c;
            c=0;
            c = b+c;//状态转移方程
            if(i==0) continue;
            auto pre=src.substr(i-1,2);
            if(pre<="25"&&pre>="10"){
                c = c+a;
            }
        }
        return c;
    }
std::string str="We think in generalities, but we live in details.";
                                           // (quoting Alfred N. Whitehead)

  std::string str2 = str.substr (3,5);     // "think",从idx3开始往后找5个

47最大价值的礼物
dp
比较好懂的例子

int maxValue(vector<vector<int>>& grid) {
        int m=grid.size();
        int n=grid[0].size();
        //定义动态规划的存储
        vector<vector<int>>dp(m,vector<int>(n,0));
        dp[0][0]=grid[0][0];
        //初始化动态规划的临界条件
        //第一行和第一列只能从一个方向到达
        for(int i=1;i<n;i++){
            dp[0][i]=dp[0][i-1]+grid[0][i];
        }  
        for(int j=1;j<m;j++){
            dp[j][0]=dp[j-1][0]+grid[j][0];
        }   
        //确定动态规划的转移方程
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                //由题意可知,只能从左边或者上边到新格子
                dp[i][j]=max(dp[i][j-1],dp[i-1][j])+grid[i][j];
            }
        }
        //返回答案
        return dp[m-1][n-1];
    }

48 字符串,没看懂
背一下

    int lengthOfLongestSubstring(string s) {
        int maxlen=0,left=0,pos=0;
        vector<bool> used(256,false);
        while(pos<s.size()){
            while(used[s[pos]]) used[s[left++]]=false;//重新开始算
            maxlen = max(maxlen, pos-left+1);
            used[s[pos++]]=true;//这个用过了
        }
        return maxlen;
    }

49丑数
dp
记一下

    int nthUglyNumber(int n) {
        vector<int> dp(n+1);
        dp[1]=1;
        int p2=1,p3=1,p5=1;
        for(int i=2;i<=n;i++){
            int n2=dp[p2]*2, n3=dp[p3]*3, n5=dp[p5]*5;
            dp[i]=min(n2,min(n3,n5));
            if(dp[i]==n2) p2++;
            if(dp[i]==n3) p3++;
            if(dp[i]==n5) p5++;
        }
        return dp[n];
    }

快速排序等基础

53

    int missingNumber(vector<int>& nums) {
        //binary search O(logn)
        //bs requires a sorted seq
        int left=0,right=nums.size()-1;
        while(left<=right){
            int mid = left + (right-left)/2;
            if(nums[mid]==mid) left = mid+1;
            else right = mid-1;
        }
        return left;
    }

94
中序遍历

   vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> stk;
        while(root!=nullptr || !stk.empty()){
            while(root!=nullptr){
                stk.push(root);
                root = root->left;
            }
            root = stk.top();
            stk.pop();
            res.push_back(root->val);
            root = root->right;
        }
        return res;
    }
    //O(n)
    //O(n), binary tree is a linked list

54
二叉搜索树的第k大节点
基于中序遍历

    int kthLargest(TreeNode* root, int k) {
        vector<int> res;
        stack<TreeNode*> stk;
        while(root!=nullptr || !stk.empty()){
            while(root!=nullptr){
                stk.push(root);
                root = root->left;
            }
            root = stk.top();
            stk.pop();
            res.push_back(root->val);
            root = root->right;
        }
        //res is the inorder traversal, 左中右
        reverse(res.begin(),res.end());
        return res[k-1];
    }

57 - II. 和为s的连续正数序列

vector<vector<int>> findContinuousSequence(int target) {
        //sliding window
        int left=1, right=1, sum=0;
        vector<vector<int>> res;
        while(left<=target/2){
            if(sum<target){
                //right slide right
                sum += right;
                right++;
            }
            else if(sum>target){
                //left slide right
                sum -= left;
                left++;
            }
            else{
                vector<int> ret;
                for(int k=left;k<right;k++){
                    ret.push_back(k);
                }
                res.push_back(ret);
                sum -= left;
                left++;
            }
        }
        return res;
    }

Offer 58 - I. 翻转单词顺序

string reverseWords(string s) {

        s+=' ';
        string temp="";
        vector<string> res;
        for(char ch:s)
        {
            if(ch == ' ')
            {
                if(!temp.empty())//temp is storing words
                {
                    res.push_back(temp);//res stores separate words
                    temp.clear();
                }
            }
            else temp += ch;//contruct words
        }
        reverse(res.begin(),res.end());
        s.clear();
        for(string &str: res){
            s += str + ' ';
        }
        s.pop_back();
        return s;

        //
        //double ptr
        
    }

27

    TreeNode* mirrorTree(TreeNode* root) {
        if(root==nullptr) return nullptr;
        TreeNode* left = root->left;
        root->left = mirrorTree(root->right);
        root->right = mirrorTree(left);
        return root;
    }
//O(N)
//O(N) 最差情况二叉树退化成链表

28

    bool isSymmetric(TreeNode* root) {
        if(root == nullptr) return true;
        return dfs(root->left,root->right);
    }
    bool dfs(TreeNode* p, TreeNode* q){
        if(p==nullptr || q==nullptr) return !p&&!q;//如果两个都是null,return true
        if(p->val != q->val) return false;
        return dfs(p->left, q->right) && dfs(p->right,q->left);
    }

29
矩阵打印

    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        if(matrix.empty()) return {};
        vector<int> res;
        int l=0;
        int r = matrix[0].size()-1;
        int t=0;
        int b=matrix.size()-1;
        while(1){
            //left->right
            for(int i=l;i<=r;i++) res.push_back(matrix[t][i]);
            if(++t > b) break;
            //top->bottom
            for(int i=t;i<=b;i++) res.push_back(matrix[i][r]);
            if(--r < l) break;
            for(int i=r;i>=l;i--) res.push_back(matrix[b][i]);
            if(--b < t) break;
            for(int i=b;i>=t;i--) res.push_back(matrix[i][l]);
            if(++l > r) break;
        }
        return res;
    }

39 哈希

    int majorityElement(vector<int>& nums) {
        //众数
        //OP1.哈希表
        //O(n)
        unordered_map<int,int> counts;
        int maj=0,cnt=0;
        for(int num:nums){
            ++counts[num];
            if(counts[num]>cnt){
                maj=num;
                cnt=counts[num];
            }
        }
        return maj;
        //OP2.数组排序
        sort(nums.beigin(),nums.end());
        return nums[nums.size()/2];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像识别技术在病虫害检测中的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分类植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物图像数据,这些数据包括健康植物的图像以及受不同病虫害影响的植物图像。 2. **图像预处理**:对收集到的图像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从图像中提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程中,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统中,可以是移动应用、网页服务或集成到智能农业设备中。 7. **实时监测**:在实际应用中,系统可以实时接收植物图像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,图像识别在病虫害检测中的应用将越来越广泛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值