专题:剑指offer

链表

JZ6 从尾到头打印链表

思路:先顺序输出到栈里面 然后再以此从栈顶弹出即可

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
#include <vector>
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        stack<int> st;
        while(head!=nullptr){
            st.push(head->val);
            head=head->next;
        }

        vector<int> res; 
        while(!st.empty()){
            res.push_back(st.top());
            st.pop();
        }
        return res;
    }
};

JZ24 反转链表

思路:借助虚拟头结点进行头插法

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 *	ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode类 
     * @return ListNode类
     */
    ListNode* ReverseList(ListNode* head) {
        // write code here
        //头插法
        ListNode* dummy = new ListNode(0);
        ListNode* cur = head;
        while(cur!=nullptr){
            ListNode* next = cur->next;

            //头插法
            cur->next=dummy->next;
            dummy->next=cur;

            cur = next;
        }

        ListNode* res = dummy->next;
        delete dummy;
        return res;
    }
};

JZ25 合并两个排序的链表

方法一:迭代法

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 *	ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pHead1 ListNode类 
     * @param pHead2 ListNode类 
     * @return ListNode类
     */
    // ListNode* dfs(ListNode* pHead1, ListNode* pHead2){

    // } 

    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {

        // write code here
        // 迭代写法
        ListNode* dummp=new ListNode(0);
        ListNode*pre =dummp;
        while(pHead1!=nullptr&&pHead2!=nullptr){
            if(pHead1->val<pHead2->val){
                ListNode* temp = new ListNode(pHead1->val);
                pre->next=temp;
                pre=temp;
                pHead1=pHead1->next;
            }else{
               ListNode* temp = new ListNode(pHead2->val);
                pre->next=temp;
                pre=temp;
                pHead2=pHead2->next;
            }
        }

        while(pHead1!=nullptr){
                ListNode* temp = new ListNode(pHead1->val);
                pre->next=temp;
                pre=temp;
                pHead1=pHead1->next;
        }

        while(pHead2!=nullptr){
               ListNode* temp = new ListNode(pHead2->val);
                pre->next=temp;
                pre=temp;
                pHead2=pHead2->next;
        }
        ListNode* res=dummp->next;
        delete dummp; 
        return res;
    }
};

方法二 递归:

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 *	ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pHead1 ListNode类 
     * @param pHead2 ListNode类 
     * @return ListNode类
     */
    // ListNode* dfs(ListNode* pHead1, ListNode* pHead2){

    // } 

    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {

        // write code here
        if(pHead1==nullptr && pHead2==nullptr){
            return nullptr;
        }else if(pHead1==nullptr && pHead2!=nullptr){
            return pHead2;
        }else if(pHead1!=nullptr && pHead2==nullptr){
            return pHead1;
        }
        // 
        if(pHead1->val<pHead2->val){
            //
            ListNode* next1=pHead1->next;
            // pHead1->next=nullptr;
            pHead1->next=Merge(next1,pHead2);
            return pHead1;
        }

        ListNode* next2=pHead2->next;
        // pHead2->next=nullptr;
        pHead2->next=Merge(pHead1,next2);
        return pHead2;
    }
};

JZ52 两个链表的第一个公共结点

方法一:循环遍历两个链表
方法二·:遍历长链表 先快走几步 后面和端链表一起同步走
方法一

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        ListNode* cur1 = pHead1;
		ListNode* cur2 = pHead2;
        while(cur1!=cur2){
			cur1= cur1==nullptr?pHead2:cur1->next;
			cur2= cur2==nullptr?pHead1:cur2->next;
		}
		return cur2;
    }
};

方法二

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        // 普通解法 就是先走多少步
		ListNode* cur1 = pHead1;
        int len1 =0;
		while(cur1!=nullptr){
			cur1=cur1->next;
			len1++;
		}

       ListNode* cur2 = pHead2;
	   int len2 =0;
	   while(cur2!=nullptr){
         cur2=cur2->next;
		 len2++;
	   }

	   int gap =abs(len1-len2);
	   // 保证pHead1指向的是长的链表
	   if(len1<len2){
		ListNode* temp=pHead1;
		pHead1=pHead2;
		pHead2=temp;
	   }
	   cur1 = pHead1;
	   while(gap--){
		cur1=cur1->next;
	   }
	   cur2 = pHead2;
	   while(cur1!=nullptr){
		if(cur1==cur2){
			return cur1;
		}
		cur1=cur1->next;
		cur2=cur2->next;

	   }
	   return cur2;


    }
};

JZ23 链表中环的入口结点
思路:快慢指针 循环体内 快指针每次走两步 慢指针每次走一步 能够相遇也就是说明有环 然后 慢指针从头开始 另外一个指针从相遇节点开始 判断是否再次相遇 不相遇 这两个指针 每次走一步 走到相遇点就是环入口。


/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        
      ListNode* slow,*fast;
      slow=fast=pHead;
      while(fast!=nullptr&&fast->next!=nullptr){
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast){
            // 存在环
            ListNode* slow = pHead;
            ListNode* cur = fast;
            while(slow!=cur){
                slow=slow->next;
                cur=cur->next;
            }
            return cur;
        }
      }
      return nullptr;
    }
};

JZ35 复杂链表的复制

参考视频
思路:使用散列表 如下

        unordered_map<RandomListNode*,RandomListNode*> mymap;
        RandomListNode* cur = pHead;
        while(cur!=nullptr){
            mymap[cur]=new RandomListNode(cur->label);
            cur=cur->next;
        }

此时节点已经构造出来了 开始准备映射节点的next,以及random关系

完整代码:

/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
class Solution {

    // RandomListNode* dfs(RandomListNode* pHead) {
    //     if (pHead == nullptr) {
    //         return nullptr;
    //     }
    //     RandomListNode* newnode = new RandomListNode(pHead->label);
    //     cout << "val:" << pHead->label << endl;
    //     newnode->next = dfs(pHead->next);
    //     newnode->random = dfs(pHead->random);

    //     return newnode;
    // }
  public:
    RandomListNode* Clone(RandomListNode* pHead) {
        // 
        unordered_map<RandomListNode*,RandomListNode*> mymap;
        RandomListNode* cur = pHead;
        while(cur!=nullptr){
            mymap[cur]=new RandomListNode(cur->label);
            cur=cur->next;
        }

        cur = pHead;
        while(cur!=nullptr){
            if(cur->next){
              mymap[cur]->next=mymap[cur->next];
            }
            if(cur->random){
              mymap[cur]->random=mymap[cur->random];
            }
            cur=cur->next;
        }
        return mymap[pHead];

    }
};

Z76 删除链表中重复的结点

思路:这里使用率pre以及cur 每次看cur以及cur->next是否相等 不相等 移动pre以及cur 如果相等 移动cur到本次循环不相等的地方


/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead) {
      ListNode* dummy = new ListNode(0);
      dummy->next = pHead;
      ListNode*pre = dummy;
      ListNode*cur = pHead;
      while(cur!=nullptr){
        if(cur->next==nullptr || cur->next->val != cur->val){
            // 准备下一次循环 pre/cur 都需要移动一格
            pre=cur;
            cur=cur->next;

        }else{
            while(cur->next!=nullptr && cur->val ==cur->next->val){
                cur=cur->next;
            }
            ListNode* nextnode = cur->next;

            // 直接跳过重复的节点 也就是pre->next直接next到不重复的节点(模拟删除)  注意pre没有移动 移动的是cur
            pre->next = nextnode;
            cur = nextnode;
        }
      }

      return dummy->next;
    }
};

JZ18 删除链表的节点

方法一:迭代法
方法二:递归

方法一

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 *	ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode类 
     * @param val int整型 
     * @return ListNode类
     */

    ListNode* deleteNode(ListNode* head, int val) {
        // write code here
        if(head==nullptr){
            return nullptr;
        }
        if(head->val!=val){
          head->next=deleteNode(head->next,val);
          return head;
        }
        return deleteNode(head->next,val);
    }
};

方法二:

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 *	ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode类 
     * @param val int整型 
     * @return ListNode类
     */

    ListNode* deleteNode(ListNode* head, int val) {
        // write code here
        ListNode* dummy =new ListNode(0);
        dummy->next=head;
        ListNode* pre = dummy;
        ListNode* cur = head;
        while(cur!=nullptr){
            if(cur->val==val){
                // 你不需要 free 或 delete 被删除的节点 题目已经指出来
                // ListNode* delenode = cur;
                cur=cur->next;
                pre->next = cur;
            }else{
                pre=cur;
                cur=cur->next;
            }
        }
        return dummy->next;
    }
};

二叉树

二叉树四部曲
1.确定是否需要返回值(和题目的递归函数函数是否有返回值无关)
2.确定遍历顺序(有返回值接的需要接住)
3.确定结束条件(注意是否存在中途直接return)
4.确定单层循环逻辑
J
Z55 二叉树的深度

思路:后序遍历

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    int TreeDepth(TreeNode* pRoot) {
		if(pRoot==nullptr){
			return 0;
		}

		int leftdep = TreeDepth(pRoot->left);
		int rightdep = TreeDepth(pRoot->right);
		return max(leftdep,rightdep)+1;
    }
};

JZ54 二叉搜索树的第k个节点
思路:中序遍历

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
#include <climits>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param proot TreeNode类 
     * @param k int整型 
     * @return int整型
     */
    int ret=INT_MAX;
    void dfs(TreeNode* proot, int &k){
        if(proot==nullptr){
            return;

        }
        dfs(proot->left,k);
        k--;
        if(k==0){
           ret=proot->val;
        }
        dfs(proot->right,k);

    }
    int KthNode(TreeNode* proot, int k) {
        // write code here
      dfs(proot,k);
      return ret==INT_MAX?-1:ret;
    }
};

JZ7 重建二叉树

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param preOrder int整型vector 
     * @param vinOrder int整型vector 
     * @return TreeNode类
     */
    TreeNode* reConstructBinaryTree(vector<int>& preOrder, vector<int>& vinOrder) {
        // write code here
        if(preOrder.size()==0){
            return nullptr;
        }
        int val = preOrder[0];
        preOrder.erase(preOrder.begin());

        int inindex =0;
        for(int i=0;i<vinOrder.size();i++){
            if(vinOrder[i]==val){
                inindex=i;
                break;
            }
        }
        /****** 下面这种写法 注意区间是左闭右开的******/
        // 中序遍历的左部分
        vector<int> vinLeftOrder(vinOrder.begin(),vinOrder.begin()+inindex);
        // 中序遍历的右部分
        vector<int> vinRightOrder(vinOrder.begin()+inindex+1,vinOrder.end());

        // 先序遍历的左部分
        vector<int> preLeftOrder(preOrder.begin(), preOrder.begin() +inindex);
        // 先序遍历的右部分
        vector<int> preRightOrder(preOrder.begin() +inindex, preOrder.end());

       // cout<<"preLeftOrder.size()"<<preLeftOrder.size()<<"  vinLeftOrder.size()"<<vinLeftOrder.size()<<"  preRightOrder.size()"<<preRightOrder.size()<<" vinRightOrder.size()"<<vinRightOrder.size()<<endl;

       TreeNode* root =new TreeNode(val);
       root->left = reConstructBinaryTree(preLeftOrder,vinLeftOrder);
       root->right = reConstructBinaryTree(preRightOrder,vinRightOrder);
       return root;
    }
};

JZ26 树的子结构

思路:先序遍历

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
bool dfs(TreeNode* pRoot1, TreeNode* pRoot2){
	if(pRoot2==nullptr) return true;
	if(pRoot1==nullptr) return false;

	if(pRoot1->val!=pRoot2->val){
		return false;
	}

	return dfs(pRoot1->left,pRoot2->left)&&dfs(pRoot1->right,pRoot2->right);


}
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) {
	if(pRoot2==nullptr) return false;
	if(pRoot1==nullptr) return false;
		if(dfs(pRoot1,pRoot2)){
			return true;
		}
        return HasSubtree(pRoot1->left,pRoot2)||HasSubtree(pRoot1->right,pRoot2);
    }
};

JZ27 二叉树的镜像

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pRoot TreeNode类 
     * @return TreeNode类
     */
    TreeNode* Mirror(TreeNode* pRoot) {
        // write code here
        if(pRoot==nullptr){
            return nullptr;
        }
        TreeNode* temp = pRoot->left;
        pRoot->left=pRoot->right;
        pRoot->right=temp;
        Mirror(pRoot->left);
        Mirror(pRoot->right);
        return pRoot;
    }
};

JZ32 从上往下打印二叉树

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
		// 也就是二叉树的层序遍历
		queue<TreeNode*> qu;
		vector<int> res;
		if(root==nullptr){
			return res;
		}
		qu.push(root);
		while(!qu.empty()){
			int len = qu.size();
			for(int i=0;i<len;i++){
				TreeNode* node = qu.front();
				res.push_back(node->val);
				qu.pop();
				if(node->left){
                   qu.push(node->left);
				}
				if(node->right){
					qu.push(node->right);
				}
			}
		}
		return res;
    }
};

JZ33 二叉搜索树的后序遍历序列

先确定根节点 然后 找到第一个可以区分左右区间的 验证当前左右分支节点是否合理(大小) 然后递归

技巧 直接右分支的左边界初始化为1

        int index = -1;
        for (int i = 0; i < sequence.size(); i++) {
            if (sequence[i] > val) {
                index = i;
                break;
            }
        }
class Solution {
  public:
    bool dfs(vector<int> sequence) {
        if (sequence.size() <= 1) {
            return true;
        }
        int val = sequence.back();
        sequence.pop_back();
        int index = -1;
        for (int i = 0; i < sequence.size(); i++) {
            if (sequence[i] > val) {
                index = i;
                break;
            }
        }

        if (index == -1) {
            // 没有右边 sequence已经处理过 移除过根节点了
            return dfs(sequence);
        }

        for (int i = index; i < sequence.size(); i++) {
            if (sequence[i] < val) {
                return false;
            }
        }
        vector<int> leftsequence(sequence.begin(), sequence.begin() + index);
        vector<int> rightsequence(sequence.begin() + index, sequence.end());
        return dfs(leftsequence) && dfs(rightsequence);
    }
    bool VerifySquenceOfBST(vector<int> sequence) {
        if(sequence.size()==0){
            return false;
        }
        return dfs(sequence); 
    }
};

上面可以发现测试用例里面 sequence是空的时候 不是搜索树 我觉得测试用例有问题 空的二叉树 应该也是二叉搜索树 在leetcodeLCR 152. 验证二叉搜索树的后序遍历序列中测试用例完善了这一点
leetcode代码因此可以更加简洁

class Solution {
public:
    bool verifyTreeOrder(vector<int>& postorder) {
        if(postorder.size()==0){
            return true;
        }
        int rootval = postorder.back();
        postorder.pop_back();
        
        int index=postorder.size();
        for(int i=0;i<postorder.size();i++){
            if(postorder[i]>rootval){
                index= i;
                break;
            }
        }
        // 左闭右开
        vector<int> left(postorder.begin(),postorder.begin()+index);
        vector<int> right(postorder.begin()+index,postorder.end());

        for(int i=0;i<left.size();i++){
            if(left[i]>rootval){
                return false;
            }
        }

        for(int i=0;i<right.size();i++){
            if(right[i]<rootval){
                return false;
            }
        }

        return verifyTreeOrder(left)&&verifyTreeOrder(right);
    }
};

JZ36 二叉搜索树与双向链表

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
	stack<TreeNode*> st;
	void dfs(TreeNode* pRootOfTree){
		if(pRootOfTree==nullptr){
			return;
		}
		dfs(pRootOfTree->right);
        st.push(pRootOfTree);
		dfs(pRootOfTree->left);

	}
public:
    TreeNode* Convert(TreeNode* pRootOfTree) {
		if(pRootOfTree==nullptr){
			return nullptr;
		}
		dfs(pRootOfTree);
         
		TreeNode* dummy=new TreeNode(-1);
		TreeNode* pre=dummy;
		while(!st.empty()){
			TreeNode* node = st.top();
			st.pop();
			cout<<"val:"<<node->val<<endl;
			node->left=nullptr;
			node->right=nullptr;

			pre->right = node;
            node->left = pre;

			pre = node;
			
		}
        TreeNode* res= dummy->right;
		res->left=nullptr;

		return res;

    }
};

JZ79 判断是不是平衡二叉树

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pRoot TreeNode类 
     * @return bool布尔型
     */
    int  dfs(TreeNode* pRoot) {
        // write code here
        if(pRoot==nullptr){
            return 0;
        }
        int leftdep = dfs(pRoot->left);
        int rightdep = dfs(pRoot->right);
        if(leftdep==-1||rightdep==-1){
            return -1;
        }
        if(abs(leftdep-rightdep)>1){
            return -1;
        }
        int curdep =max(leftdep,rightdep)+1;
        
        return curdep;

    }
    bool IsBalanced_Solution(TreeNode* pRoot) {
        // write code here
        int dep = dfs(pRoot);
        return dep==-1?false:true;

    }
};

JZ8 二叉树的下一个结点

JZ78 把二叉树打印成多行

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pRoot TreeNode类 
     * @return int整型vector<vector<>>
     */
    vector<vector<int> > Print(TreeNode* pRoot) {
        // write code here
        vector<vector<int> > ret;
        if(pRoot==nullptr){
            return ret;
        }
        queue<TreeNode*> qu;
        qu.push(pRoot);
        while(!qu.empty()){
            int len = qu.size();
            vector<int>  temp;
            for(int i=0;i<len;i++){
                TreeNode* node =qu.front();
                qu.pop();

                temp.push_back(node->val);

                if(node->left){
                  qu.push(node->left);
                }
                if(node->right){
                  qu.push(node->right);
                }
            }
            ret.push_back(temp);
        }
        return ret;
    }
};

JZ37 序列化二叉树

这个题目和leetcode的题目是一样的 只不过给的函数返回值类型不一样而已 leetcode297二叉树的序列化与反序列化
leetcode:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Codec {
public:

    // Encodes a tree to a single string.
    void serializeHelper(TreeNode* root,string &str){
        // 先序遍历
        if(root==NULL){
            str=str+"#"+",";
            return;
        }
        str=str+to_string(root->val)+ ",";
        serializeHelper(root->left,str);
        serializeHelper(root->right,str);
    }
    string serialize(TreeNode* root) {
        string str;
        serializeHelper(root,str);
        return str;
    }

    // Decodes your encoded data to tree.
    vector<string> getVFromStr(string data){
        vector<string> res;
        string temp ="";
        for(int i=0;i<data.size();i++){
            if(data[i]==','){
                res.push_back(temp);
                temp.clear();
            }else{
                temp=temp+data[i];
            }
        }
        return res;
    }

    TreeNode*DecodeTreeNodeFromV(vector<string> num,int &i){
        if(num[i]=="#"){
            i++;
            return NULL;
        }
        TreeNode* node = new TreeNode(stoi(num[i]));
        i++;
        node->left = DecodeTreeNodeFromV(num,i);
        node->right = DecodeTreeNodeFromV(num,i);
        return node;
    }
    TreeNode* deserialize(string data) {
        vector<string> num = getVFromStr(data);
        // for(auto item:num){
        //     cout<<item<<"  ";

        // }
        // cout<<endl;
        int startindex =0;
        TreeNode* root = DecodeTreeNodeFromV(num,startindex);
        return root;
    }
};

// Your Codec object will be instantiated and called as such:
// Codec ser, deser;
// TreeNode* ans = deser.deserialize(ser.serialize(root));

回看牛客里面是char参数 也就是见char 和string相互转换就可以将代码直接复制到牛客上面了
str==》char *

        string str =".."
        char * retc =new char[str.length()+1];
        strcpy(retc, str.c_str());

char * ==》string

char *pc;
string data(pc);

完整代码:

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
#include <cstring>
class Solution {
public:
    void serializeHelper(TreeNode* root,string &str){
        // 先序遍历
        if(root==NULL){
            str=str+"#"+",";
            return;
        }
        str=str+to_string(root->val)+ ",";
        serializeHelper(root->left,str);
        serializeHelper(root->right,str);
    }
    string serialize(TreeNode* root) {
        string str;
        serializeHelper(root,str);
        return str;
    }

    // Decodes your encoded data to tree.
    vector<string> getVFromStr(string data){
        vector<string> res;
        string temp ="";
        for(int i=0;i<data.size();i++){
            if(data[i]==','){
                res.push_back(temp);
                temp.clear();
            }else{
                temp=temp+data[i];
            }
        }
        return res;
    }

    TreeNode*DecodeTreeNodeFromV(vector<string> num,int &i){
        if(num[i]=="#"){
            i++;
            return NULL;
        }
        TreeNode* node = new TreeNode(stoi(num[i]));
        i++;
        node->left = DecodeTreeNodeFromV(num,i);
        node->right = DecodeTreeNodeFromV(num,i);
        return node;
    }
    TreeNode* deserialize(string data) {
        vector<string> num = getVFromStr(data);
        // 测试打印
        // for(auto item:num){
        //     cout<<item<<"  ";
        // }
        // cout<<endl;
        int startindex =0;
        TreeNode* root = DecodeTreeNodeFromV(num,startindex);
        return root;
    }

    char* Serialize(TreeNode *root) {
        string str =serialize(root);
        char * retc =new char[str.length()+1];
        strcpy(retc, str.c_str());
        return retc;
    }
    TreeNode* Deserialize(char *str) {
        string data(str);
        return deserialize(data);
    }

};

JZ84 二叉树中和为某一值的路径(三)

思路:先序遍历二叉树 然后争对每个节点再次先序遍历

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @param sum int整型 
     * @return int整型
     */
     int count =0;
     void dfs(TreeNode* root, int sum){
        if(root==nullptr){
            return;
        }
        sum=sum-root->val;
        if(sum==0){
            count++;

        }
        dfs(root->left,sum);
        dfs(root->right,sum);

     }

     void preorder(TreeNode* root, int sum){
        if(root==nullptr){
            return;

        }
        // write code here
        dfs(root,sum);
        preorder(root->left,sum);
        preorder(root->right,sum);
     }
    int FindPath(TreeNode* root, int sum) {

        // write code here
        preorder(root,sum);
        return count;

    }
};

JZ86 在二叉树中找到两个节点的最近公共祖先

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @param o1 int整型 
     * @param o2 int整型 
     * @return int整型
     */
     TreeNode* dfs(TreeNode* root, int o1, int o2){
        if(root==nullptr){
            return nullptr;
        }
        if(root->val==o1||root->val==o2){
            return root;
        }
        TreeNode* leftchild = dfs(root->left,o1,o2);
        TreeNode* rightchild = dfs(root->right,o1,o2);

        if(leftchild==nullptr && rightchild==nullptr){
            return nullptr;
        }else if(leftchild!=nullptr && rightchild==nullptr){
            return leftchild;
        }else if(leftchild==nullptr && rightchild!=nullptr){
            return rightchild;
        }
        return root;
     }
    int lowestCommonAncestor(TreeNode* root, int o1, int o2) {
        // write code here
        TreeNode* node = dfs(root,o1,o2);
        return node->val;
        
    }
};

JZ68 二叉搜索树的最近公共祖先

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @param p int整型 
     * @param q int整型 
     * @return int整型
     */
    //  -1 就是代表空
    TreeNode* dfs(TreeNode* root, int p, int q){
        if(root==nullptr){
            return nullptr;
        }
        if(root->val == p || root->val == q){
            return root;
        }

        if(root->val>p && root->val>q){
            return dfs(root->left,p,q);
        }  
        if(root->val<p && root->val<q){
           return dfs(root->right,p,q);
        }
        // 左右两边各一个 也就是说此时root就是最近公共祖先
        return root;
    }
    int lowestCommonAncestor(TreeNode* root, int p, int q) {
        // write code here
        TreeNode* ndoe = dfs(root,p,q);
        return ndoe->val;
    }
};

队列 & 栈

JZ9 用两个栈实现队列
思路:stack1只负责push

class Solution
{
public:
    void push(int node) {
        stack1.push(node);
    }

    int pop() {
        if(stack2.empty()){
            while(!stack1.empty()){
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
        int val = stack2.top();
        stack2.pop();
        return val;
        
    }

private:
    // 插入
    stack<int> stack1;
    stack<int> stack2;
};

JZ30 包含min函数的栈
思路: st1 只负责push 每次栈st2的时候 需要比较st2栈顶数据 压入小数据

class Solution {
public:
    void push(int value) {
        st1.push(value);
        if(!st2.empty()){
            int top= st2.top();
            if(top>value){
                st2.push(value);
            }else{
                st2.push(top);
            }

        }else{
            st2.push(value);
        }
        
    }
    void pop() {
        st1.pop();
        st2.pop();
        
    }
    int top() {
        return st1.top();
    }
    int min() {
        return st2.top();
        
    }
    stack<int> st1;
    stack<int> st2;
};

JZ31 栈的压入、弹出序列

刚开始没有理清思路 以为 push的元素 如果在pop中出来了 那么push该之前的元素也一定出来了
发现还有这种情况
[2,1,0],[1,2,0] 明显这个是多余的 但是和思路不符合 所以上面这个思路是错的

正确思路:借助栈 每次入st栈后 如果发现栈顶元素和popV中将要出栈的元素一致 直接st.pop 直到和opV中将要出栈的元素不一致时候 进入下一轮循环 最终直接判断st是否为空即可
可以参考视频
完整代码:

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pushV int整型vector 
     * @param popV int整型vector 
     * @return bool布尔型
     */
    bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
        // write code here
        stack<int> st;
        int popindex =0;
        for(int i=0;i<pushV.size();i++){
            // if(st.empty()){
              st.push(pushV[i]);
            // }
            while(!st.empty() && st.top() ==popV[popindex]){
                st.pop();
                popindex++;
            }
        }
        return st.empty();

    }
};

JZ73 翻转单词序列

JZ59 滑动窗口的最大值

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param num int整型vector 
     * @param size int整型 
     * @return int整型vector
     */
    vector<int> maxInWindows(vector<int>& num, int size) {
        // write code here
        vector<int> res;
        // 单纯的是因为测试用例里面有size是0 因此需要单独拎出来
        if(size==0){
            return res;
        }
        // 不严格的单调递减队列(使用双向队列deque) 队列里面存元素下标  弹出条件是 num[i]   >num[qu.back()] 此时弹出qu.back()
        deque<int> qu;

        for(int i=0;i<num.size();i++){
            while(!qu.empty()&&num[i]>num[qu.back()]){
                qu.pop_back();
            }
            qu.push_back(i);
            
            if(qu.back()-qu.front()+1>size){
                qu.pop_front();
            }

            if(i+1>=size){
              res.push_back(num[qu.front()]);
            }
        }
        return res;
    }
};

搜索算法

JZ53 数字在升序数组中出现的次数

寻找左边界的时候

 int mid = (left+right)/2;

需要注意寻找右边界的时候

int mid = (left+right+1)/2;
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型vector 
     * @param k int整型 
     * @return int整型
     */
    int GetNumberOfK(vector<int>& nums, int k) {
        // write code here
        if(nums.size()==0){
            return 0;
        }
        // 寻找左边界
        int left =0;
        int right =nums.size()-1;
        while(left<right){
            // 这种写法 会向左边靠拢
            int mid = (left+right)/2;
            if(nums[mid]>k){
                right=mid -1;
            }else if(nums[mid]<k){
                left=mid+1;
            }else if(nums[mid]==k){
              right=mid;
            }
        }
        // cout<<"left:"<<left<<endl;
        if(nums[left]!=k){
            return 0;
        }

        int leftindex = left;
        // 有边界
        left =0;
        right =nums.size()-1;
        while(left<right){
            // 此时相等的时候 会向右边靠拢
            int mid = (left+right+1)/2;
            if(nums[mid]>k){
                right=mid -1;
            }else if(nums[mid]<k){
                left=mid+1;
            }else if(nums[mid]==k){
              left=mid;
            }
        }
        // cout<<"right"<<left<<endl;
        int rightindex = left;

        return rightindex-leftindex+1;
    }
};

JZ11 旋转数组的最小数字

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型vector 
     * @return int整型
     */
    int minNumberInRotateArray(vector<int>& nums) {
        // write code here
        int left = 0;
        int right = nums.size()-1;
        while(left<right){
            int mid = (left+right)/2;
             if(nums[mid]>nums[right]){
                left=mid+1;
             }else if(nums[mid]<nums[right]){
                right = mid;
             }else{
                right--;
             }
             cout<<"left:"<<left<<endl;
        }

        return nums[left];
    }
};

JZ38 字符串的排列

思路:回溯算法 排列问题 并且需要数层去重 (先排序 再借助used[i]数组)

#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param str string字符串 
     * @return string字符串vector
     */
     vector<string> res;
     string path;
     void backtracking(string str,vector<bool> &used){
        if(path.size()==str.size()){
          res.push_back(path);
        //   return;
        }
        for(int i=0;i<str.size();i++){
            if(i-1>=0&&str[i]==str[i-1]&&used[i-1]==false){
                continue;
            }
            if(used[i]==true){
                continue;
            }
            used[i]=true;
            path=path+str[i];
            
            // cout<<"i:"<<i<<endl;
            backtracking(str,used);

            path.pop_back();
            used[i]=false;
        }

     }
    vector<string> Permutation(string str) {
        // write code here
        // 数层去重 全排列
        // 先排序
        sort(str.begin(),str.end(),[](char a,char b){
            return a<b;
        });
        vector<bool> used(str.size(),false);
        backtracking(str, used);
        return res;
    }
};

JZ44 数字序列中某一位的数字

动态规划

JZ85 连续子数组的最大和(二)
思路:先用动态规范求的每个结尾的最大和 然后遍历dp 从最大和下标往前找 看有没有是最大和 找到后比较最大长度即可

#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param array int整型vector 
     * @return int整型vector
     */
    vector<int> FindGreatestSumOfSubArray(vector<int>& array) {
        // write code here
        // // dp[i]以array[i]的结尾的连续的最长和

        // if(dp[i-1]>=0){
        //     dp[i]=dp[i-1]+array[i];
        // }else{
        //     dp[i]=array[i];
        // }

        // // 初始化
        // dp[0]=array[0];

        // // 遍历顺序 从左到右

        // // 返回值 遍历dp[i] 找到最大和的结尾下边 向前查找 

        // //
        vector<int> dp(array.size(),0);
        dp[0]=array[0];
        for(int i=1;i<array.size();i++){
            if(dp[i-1]>=0){
                dp[i]=dp[i-1]+array[i];
            }else{
                dp[i]=array[i];
            }
        }
        // int rightindex =0;
        int summax=INT_MIN;
        vector<int> rightindexList;
        for(int i=0;i<dp.size();i++){
            if(dp[i]>summax){
                rightindexList.clear();
                rightindexList.push_back(i);
                summax=dp[i];
            }else if(dp[i]==summax){
                rightindexList.push_back(i);
            }
        }
        // int maxlen =0;
        vector<int> res;
        for(auto rightindex: rightindexList){
            int currntsum = 0;
            vector<int> temp;
            for(int j=rightindex;j>=0;j--){
                currntsum=currntsum+array[j];
                temp.push_back(array[j]);
                if(currntsum==summax){
                    // 取最大的
                    if(temp.size()>res.size()){
                        res=temp;
                    }
                }
            }

        }
        reverse(res.begin(),res.end());
        return res;
    }
};

JZ69 跳台阶

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param number int整型 
     * @return int整型
     */
    int jumpFloor(int number) {
        // write code here
        // dp[i] 跳上第i借台阶 有dp[i]中方法

        // dp[i]=dp[i-1]+dp[i-2];

        // dp[0],dp[1]

        // // 从左到右

        // dp[n]

        vector<int> dp(number+1,0);
        dp[0]=1;
        dp[1]=1;
        for(int i=2;i<=number;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[number];
    }
};

JZ10 斐波那契数列

#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 
     * @return int整型
     */
    int Fibonacci(int n) {
        // write code here
        // dp[i]=dp[i-1]+dp[i-2];
        vector<int> dp(n+1,0);
        dp[0]=0;
        dp[1]=1;
        for(int i=2;i<=n;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
};

JZ71 跳台阶扩展问题
思路:完全背包 也就是元素可以重复 并且 是排列问题l

#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param number int整型 
     * @return int整型
     */
    int jumpFloorII(int number) {
        // write code here
        // 1,2,3...n  组成和为n的不同排列数有多少==》完全背包 也就是元素可以重复 并且 是排列问题
        vector<int> dp(number+1,0);
        dp[0]=1;
        for(int i=1;i<=number;i++){
            for(int j=1;j<=number;j++){
                if(i-j>=0){
                  dp[i]=dp[i]+dp[i-j];
                }
            }
        }
        return dp[number];
    }
};

JZ70 矩形覆盖

#include <vector>
class Solution {
public:
    int rectCover(int number) {

        // dp[n]..

        vector<int> dp(number+1,0);
        dp[1]=1;
        dp[2]=2;
        for(int i=3;i<=number;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[number];

    }
};

JZ47 礼物的最大价值

思路:dp[i][j]=max(dp[i][j-1],dp[i-1][j])+grid[i][j]; 看到这个就想到遍历顺序 从上到下 从左到右

#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param grid int整型vector<vector<>> 
     * @return int整型
     */
    int maxValue(vector<vector<int> >& grid) {
        // write code here
        // dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
         
        // 初始化
        // 第一行
        vector<vector<int>> dp(grid.size(),vector<int>(grid[0].size(),0));
        int hang=0;
        for(int j=0;j<grid[0].size();j++){
            hang=hang+grid[0][j];
            dp[0][j]=hang;
        }

        int lie=0;
        for(int i=0;i<grid.size();i++){
            lie=lie+grid[i][0];
            dp[i][0]=lie;
        }

        for(int i=1;i<grid.size();i++){
            for(int j=1;j<grid[0].size();j++){
                dp[i][j]=max(dp[i][j-1],dp[i-1][j])+grid[i][j];

            }
        }
        return dp[grid.size()-1][grid[0].size()-1];
    }
};

JZ48 最长不含重复字符的子字符串

#include <vector>
using namespace std;
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param s string字符串 
     * @return int整型
     */
    int lengthOfLongestSubstring(string s) {
        // write code here
        int count=0;
        unordered_set<char> myset;
        int i=0;
        for(int j=0;j<s.size();j++){
            while(myset.count(s[j])!=0){
                myset.erase(s[i]);
                i++;
            }
            myset.insert(s[j]);
            count=max(count,j-i+1);
        }
        return count;
    }
};

JZ46 把数字翻译成字符串

方法一:回溯法 -字符串的分割类型

    // 回溯算法 字符串的分割
    int count =0;
    void backtracking(string nums,int statri){
        if(statri==nums.size()){
            count++;
            return;
        }
        for(int i=statri;i<nums.size();i++){
            string substr=nums.substr(statri,i-statri+1);
            // cout<<"-nums-:"<<nums<<"--"<<statri<< "--"<<i<<"--长度"<< i-statri+1<< "  substr:"<<stoi(substr)<<endl;
            if(stoi(substr)<=0||stoi(substr)>26){
                // 没有意义 不用再向后面切割了
                break;
            }
            backtracking(nums,i+1);
        }

    }
    int solve(string nums) {
        // write code here
        backtracking(nums,0);
        return count;
    }

方法二:动态规范
状态转移方程 dp[i]=dp[i-1]+dp[i-2];
但是注意以下前提

            // dp[i]=dp[i-1]+dp[i-2];
            int val1,val2;
            if(nums[i]=='0'){
               val1=0;
            }else{
                val1=dp[i-1];
            }
            string str2;
            str2=str2+nums[i-1]+nums[i];
            if(stoi(str2)<10||stoi(str2)>=27){
                val2=0;
            }else{
                val2=dp[i-2];
            }

            dp[i]=val1+val2;

完整代码

#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 解码
     * @param nums string字符串 数字串
     * @return int整型
     */

    int solve(string nums) {
        // write code here
        // backtracking(nums,0);
        // return count;

        // dp[i]=dp[i-1]+dp[i-2]

        vector<int> dp(nums.size(),0);
        if(nums[0]=='0'){
            dp[0]=0;
        }else{
            dp[0]=1;
        }

        string temp = nums.substr(0,2);
        if(stoi(temp)>=1&&stoi(temp)<=26 && temp[1]!='0'){
            dp[1]=dp[0]+1;
        }else{
            dp[1]=dp[0];
        }

        for(int i=2;i<nums.size();i++){
            // dp[i]=dp[i-1]+dp[i-2];
            int val1,val2;
            if(nums[i]=='0'){
               val1=0;
            }else{
                val1=dp[i-1];
            }
            string str2;
            str2=str2+nums[i-1]+nums[i];
            if(stoi(str2)<10||stoi(str2)>=27){
                val2=0;
            }else{
                val2=dp[i-2];
            }

            dp[i]=val1+val2;
        }
        return dp[nums.size()-1];
                
    }
};

图算法(主要就是回溯)

JZ12 矩阵中的路径

图算法里面代码:

vector<vector<int>> dxy = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
....
for (int i = 0; i < dxy.size(); i++) {
赋值1
赋值2
dfs(..);
回溯赋值2
回溯赋值1
}
...
class Solution {
  public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param matrix char字符型vector<vector<>>
     * @param word string字符串
     * @return bool布尔型
     */



    vector<vector<int>> dxy = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    bool isValid(vector<vector<char>>& matrix,int itemi,int itemj, int equalindex, string word){
        // 是否越界
        if (itemi < 0 || itemi >= matrix.size() || itemj < 0 || itemj >= matrix[0].size() ) {
            return false;
        }
        // 是否单词匹配
        if(matrix[itemi][itemj]!=word[equalindex]){
            return false;
        }
        return true;
    }
    bool dfs(vector<vector<char> >& matrix, vector<vector<bool> > used, int starti,
             int startj, int equalindex, string word) {
        if (equalindex == word.size()) {
            return true;
        }

        for (int i = 0; i < dxy.size(); i++) {
            int itemi = starti + dxy[i][0];
            int itemj = startj + dxy[i][1];
            
            if (!isValid(matrix,  itemi,  itemj,  equalindex, word)) {
                continue;
            }

            if (used[itemi][itemj] == true) {
                // cout<<"该位置 已经遍历过了"<<"  itemi:  "<<itemi<<"  itemj:  "<<itemj<<endl;
                continue;
            }

            used[itemi][itemj] = true;

            if(dfs(matrix, used, itemi, itemj, equalindex+1,word)){
                return true;
            }
            used[itemi][itemj] = false;
        }
        return false;


    }
    bool hasPath(vector<vector<char> >& matrix, string word) {
        // write code here
        vector<vector<bool> > used(matrix.size(), vector<bool>(matrix[0].size(),
                                   false));
        for (int i = 0; i < matrix.size(); i++) {
            for (int j = 0; j < matrix[0].size(); j++) {
                if(word[0]!=matrix[i][j]){
                    continue;
                }

                used[i][j] = true;
                if(dfs(matrix, used, i, j, 1,word)){
                    return true;
                };
                used[i][j] = false;
            }
        }
        return false;
    }


};

JZ13 机器人的运动范围

#include <vector>
class Solution {
public:
    vector<vector<int>> dxy{{0,1},{0,-1},{1,0},{-1,0}};
    int getValueFrIndex(int start){
        int ret =0;
        while(start!=0){
            ret=ret+start%10;
            start=start/10;
        }
        return ret;
    }

    bool isValid(vector<vector<int>> matrix,int starti,int startj,int threshold){
        if(starti<0||starti>=matrix.size() || startj<0||startj>=matrix[0].size()){
            return false;
        }
        if(getValueFrIndex(starti)+getValueFrIndex(startj)>threshold){
            return false;
        }
        return true;
    }

    void dfs(vector<vector<int>> &matrix,int starti,int startj,int &count,int threshold){

        for(int i=0;i<dxy.size();i++){
            int itemi = starti+dxy[i][0];
            int itemj = startj+dxy[i][1];
            if(!isValid(matrix,itemi,itemj,threshold)){
                continue;
            }
            // 之前访问过
            if(matrix[itemi][itemj]==-1){
                continue;
            }
            matrix[itemi][itemj]=-1;
            count++;
            dfs(matrix,itemi,itemj,count,threshold);
        }
    }
    int movingCount(int threshold, int rows, int cols) {
        vector<vector<int>> matrix(rows,vector<int>(cols,0));
        int count =1;
        matrix[0][0]=-1;
        dfs(matrix,0,0,count,threshold);
        // ************输出matrix************
        // for(int i=0;i<matrix.size();i++){
        //   for(int j=0;j<matrix[0].size();j++){
        //     cout<<matrix[i][j]<<"  ";
        //   }
        //   cout<<endl;
        // }
        return count;
    }
};

JZ3 数组中重复的数字

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param numbers int整型vector 
     * @return int整型
     */
    int duplicate(vector<int>& numbers) {
        // write code here

        // 思路:每次将元素放到正确的位置上面

        for(int i=0;i<numbers.size();i++){
                while(numbers[i]!=i &&numbers[i]!=numbers[numbers[i]]){
                    int index1 =i;
                    int index2=numbers[i];

                    int temp =numbers[index1];
                    numbers[index1]=numbers[index2];
                    numbers[index2] = temp;
                }
                if(numbers[i]!=i){
                    return numbers[i];
                }

        }
        return -1;
        
    }
};

JZ51 数组中的逆序对

JZ40 最小的K个数

#include <functional>
#include <queue>
#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param input int整型vector 
     * @param k int整型 
     * @return int整型vector
     */
    vector<int> GetLeastNumbers_Solution(vector<int>& input, int k) {
        // write code here
        // priority_queue<int,vector<int>,less<int>> qu;

        priority_queue<int,vector<int>,less<int>> qu;

        for(int i=0;i<input.size();i++){
            qu.push(input[i]);
            if(qu.size()>k){
                qu.pop();
            }
        }
        vector<int>  res;
        while(!qu.empty()){
            res.push_back(qu.top());
            qu.pop();
        }
        reverse(res.begin(),res.end());
        return res;
    }
};

JZ41 数据流中的中位数

#include <functional>
#include <queue>
class Solution {
public:
    void balance(priority_queue<int,vector<int>,less<int>> &maxqu,priority_queue<int,vector<int>,greater<int>> &minqu){
        if(abs((int)(maxqu.size()-minqu.size()))<=1){
            return;
        }
        if(maxqu.size()>minqu.size()){
            minqu.push(maxqu.top());
            maxqu.pop();
        }else{
            maxqu.push(minqu.top());
            minqu.pop();
        }


    }
    void Insert(int num) {
        if(minqu.size()==0){
            minqu.push(num);
            return;
        }

        if(maxqu.size()==0){
            if(num>minqu.top()){
                // 需要减min里面的堆顶元素出堆 放到maxqu里面
                int topvalue = minqu.top();
                maxqu.push(topvalue);
                minqu.pop();

                minqu.push(num);

            }else{
               maxqu.push(num);
            }
            return;
        }
        if(num>minqu.top()){
            minqu.push(num);
        }else{
            maxqu.push(num);
        }
        balance(maxqu,minqu);
    }

    double GetMedian() { 
        // cout<<"maxqu:"<<maxqu.size()<<"minqu:"<<minqu.size()<<endl;
        if(maxqu.size()>minqu.size()){
            return maxqu.top();
        } else if(maxqu.size()<minqu.size()){
            return minqu.top();
        }else{
            int va1=maxqu.top();
            int va2= minqu.top();
            // cout<<"va1:"<<va1<<"va2:"<<va2<<endl;
            return ((float)va1+va2)/2;
        }
    
    }
    priority_queue<int,vector<int>,less<int>> maxqu;

    priority_queue<int,vector<int>,greater<int>> minqu;
};

位运算

JZ65 不用加减乘除做加法
可以参考视频

class Solution {
public:
    int Add(int num1, int num2)
    {
        // 进位
        int n1 =(num1&num2)<<1;
        // 不进位的值
        int n2=num1^num2;
        return n1==0?n2:Add(n1,n2);
    }
};

JZ15 二进制中1的个数

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 
     * @return int整型
     */
    int NumberOf1(int n) {
        // write code here
        int count =0;
        while(n!=0){
            n=n&(n-1);
            count++;
        }
        return count;
    }
};

JZ16 数值的整数次方

JZ56 数组中只出现一次的两个数字

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型vector 
     * @return int整型vector
     */
    vector<int> FindNumsAppearOnce(vector<int>& nums) {
        // write code here
        int res1=0;
        for(auto num:nums){
            res1=res1^num;
        }
        // res1二进制右边的第一个1
        int rightone = 1;
        //找到两个数不相同的第一位
        while((rightone & res1) == 0)
            rightone <<= 1;
        int a=0;
        int b=0;
        for(auto num:nums){
            cout<<"num:"<<num<<"  --------------:"<<endl;
            if((num&rightone)==rightone){
                a=a^num;
            }else{
                b=b^num;
            }
        }
        if(a<b){
            return {a,b};
        }
        return {b,a};
    }
};

JZ64 求1+2+3+…+n

class Solution {
public:
int sum=0;
    int Sum_Solution(int n) {
        (n!=0) && Sum_Solution(n-1);
        sum=sum+n;
        // cout<<"sum:"<<sum<<endl;
        return sum;
    }
};

模拟

JZ29 顺时针打印矩阵

这种图的遍历

遍历上下左右

vector<vector<int>> dxy{{0,1},{1,0},{0,-1},{-1,0}};

backtrack中

for(int i=0;i<dxy.size();i++){
....
}

完整代码

class Solution {
public:
    vector<int> res;
    vector<vector<int>> dxy{{0,1},{1,0},{0,-1},{-1,0}};
    bool isValid(vector<vector<int> > &matrix,int itenmi,int itenmj){
        if(itenmi<0||itenmi>=matrix.size()||itenmj<0||itenmj>=matrix[0].size()){
            return false;
        }
        return true;
    }
    void backtracking(vector<vector<int>> &matrix,vector<vector<bool>>& used,int starti,int startj,int fangxiang){
        for(int i=0;i<dxy.size();i++){
            fangxiang=(fangxiang+i)%4;
            int itenmi = starti+dxy[fangxiang][0];
            int itenmj = startj+dxy[fangxiang][1];
            if(!isValid(matrix,  itenmi,  itenmj)){
                continue;
            }
            if(used[itenmi][itenmj]==true){
                continue;
            }
            used[itenmi][itenmj]=true;
            res.push_back(matrix[itenmi][itenmj]);
            backtracking(matrix,used,itenmi,itenmj,fangxiang);

        }


    }
    vector<int> printMatrix(vector<vector<int> > matrix) {
      // 单纯是因为测试用例有[[]] 因此需要单独拎出来
      if(matrix.size()==0||matrix[0].size()==0){
        return {};
      }
      vector<vector<bool>> used(matrix.size(),vector<bool>(matrix[0].size(),false));
      used[0][0]=true;
      res.push_back(matrix[0][0]);
      backtracking(matrix,used,0,0,0);
      return res;
    }
};

JZ61 扑克牌顺子
思路:maxright-minleft<=4 另外 不存在初0以外的任何重复数字

class Solution {
public:
    bool IsContinuous( vector<int> nums )
    {
      int minleft =INT_MAX;
      int maxright=INT_MIN;
      unordered_set<int> myset;
      for(int i=0;i<nums.size();i++){
        if(nums[i]==0){
            continue;
        }
        if(myset.count(nums[i])>0){
            return false;
        }
        myset.insert(nums[i]);
        minleft=min(minleft,nums[i]);
        maxright=max(maxright,nums[i]);
      }
      return  maxright-minleft<=4;
    }
};

*JZ20 表示数值的字符串*

其他算法

JZ66 构建乘积数组
思路动态规划

res[i]=dpleft[i]*dpright[i];

完整代码

#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param A int整型vector 
     * @return int整型vector
     */
    vector<int> multiply(vector<int>& A) {
        // write code here
        vector<int> dpleft(A.size(),0);
        dpleft[0]=1;
        for(int i=1;i<A.size();i++){
           dpleft[i]=dpleft[i-1]*A[i-1];
        }

        vector<int> dpright(A.size(),0);
        dpright[A.size()-1]=1;
        for(int j=A.size()-2;j>=0;j--){
            dpright[j]=dpright[j+1]*A[j+1];
        }

        vector<int> res(A.size(),0);
        for(int i=0;i<A.size();i++){
           res[i]=dpleft[i]*dpright[i];
        }
        return res;
    }
};

JZ50 第一个只出现一次的字符

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param str string字符串 
     * @return int整型
     */
    int FirstNotRepeatingChar(string str) {
        // write code here
        unordered_map<int,int> mymap;
        for(auto c:str){
            mymap[c]++;
        }
        for(int i=0;i<str.size(); i++){
            if(mymap[str[i]]==1){
                return i;
            }
        }
        return -1;
    }
};

JZ5 替换空格

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param s string字符串 
     * @return string字符串
     */
    string replaceSpace(string s) {
        // write code here
        string str;
        for(auto c:s){
            if(c==' '){
                str=str+"%20";

            }else{
                str=str+c;
            }

        }
        return str;
    }
};

JZ21 调整数组顺序使奇数位于偶数前面(一)

JZ39 数组中出现次数超过一半的数字

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) 
    {
        //使用投票法
        
        int count=0;
        int ret=0;
        for(int i=0;i<numbers.size();i++)
        {
            
            if(count==0)
            {
                ret=numbers[i];
            }
            
            if(ret==numbers[i])
            {
                count++;
            }else{
                count--;
            }
        }
        return ret;
// 题目说一定有众数 并且众数》numbers.size()/2 因此不需要下面的代码
// //         cout<<"ret="<<ret<<endl;
//         int targetCount=0;
//         for(int i=0;i<numbers.size();i++)
//         {
//             if(numbers[i]==ret)
//             {
//                 targetCount++;
//             }
//         }
        
//         return targetCount>numbers.size()/2? ret:0;
    }
};

JZ43 整数中1出现的次数(从1到n整数中1出现的次数)

JZ45 把数组排成最小的数

在内置函数中

auto cmp=[](int a,int b){
            return to_string(a)+to_string(b) <to_string(b)+to_string(a)

完整代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param numbers int整型vector 
     * @return string字符串
     */

    string PrintMinNumber(vector<int>& numbers) {
        // write code here
        sort(numbers.begin(),numbers.end(),[](int a,int b){
            return to_string(a)+to_string(b) <to_string(b)+to_string(a);
        });

        string str;
        for(auto num:numbers){
            str=str+to_string(num);
        }
        return str;
    }
};

JZ49 丑数

class Solution {
public:
    int nthUglyNumber(int n) {
        vector<int> dp(n+1,0);
        dp[1]=1;
        int a=1;
        int b=1;
        int c =1;
        for(int i=2;i<=n;i++){
            dp[i]=min({dp[a]*2,dp[b]*3,dp[c]*5});
            if(dp[i]==dp[a]*2){
                a++;
            }
            if(dp[i]==dp[b]*3){
                b++;
            }
            if(dp[i]==dp[c]*5){
                c++;
            }
        }
        for(auto val:dp){
            cout<<val<<"  ";

        }
        return dp[n];
    }
};

JZ74 和为S的连续正数序列

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param sum int整型 
     * @return int整型vector<vector<>>
     */
    vector<vector<int> > FindContinuousSequence(int sum) {
        // write code here
        int i=1;
        int currentsum =0;
        vector<vector<int> > res;
        for(int j=1;j<=sum-1;j++){
            currentsum=currentsum+j;
            while(currentsum>sum){
                currentsum=currentsum-i;
                i++;
            }
            if(currentsum==sum){
                vector<int> tempv;
                for(int tempi=i;tempi<=j;tempi++){
                    tempv.push_back(tempi);
                }
                res.push_back(tempv);
            }

        }
        return res;
    }
};

JZ57 和为S的两个数字

#include <vector>
class Solution {
public:
    vector<int> FindNumbersWithSum(vector<int> array,int sum) {
        // 
        unordered_set<int> myset;
        for(int i=0;i<array.size();i++){
           int target = sum-array[i];
           if(myset.count(target)>0){
              return vector<int>{array[i],target};
           }
           myset.insert(array[i]);
        }
        return {};
        
    }
};

JZ58 左旋转字符串
方法一:不借助额外数组进行自身翻转(掌握)

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param str string字符串 
     * @param n int整型 
     * @return string字符串
     */
    string LeftRotateString(string str, int n) {
        // write code here
        if(str.size()==0){
            return "";

        }
        n=n%str.size();

        reverse(str.begin(),str.end());
        // cout<<str<<endl;
        reverse(str.end()-n,str.end());
        // cout<<str<<endl;
        reverse(str.begin(),str.end()-n);
        // cout<<str<<endl;
        return str;
    }
};

方法二:直接找到左半边 右半边进行拼接

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param str string字符串 
     * @param n int整型 
     * @return string字符串
     */
    string LeftRotateString(string str, int n) {
        if(str.size()==0){
            return "";
        }
        // write code here
        int len = n%str.size();
        string temp1 = str.substr(0,len);
        string temp2 = str.substr(len);
        return temp2+temp1;
    }
};

Z62 孩子们的游戏(圆圈中最后剩下的数)

#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 
     * @param m int整型 
     * @return int整型
     */
     int dfs(vector<int> &nums,int m){
        if(nums.size()==1){
            return nums[0];
        }
        int index = (m-1)%nums.size();
        vector<int> left(nums.begin(),nums.begin()+index);
        vector<int> right(nums.begin()+index+1,nums.end());
        
        right.insert(right.end(), left.begin(), left.end());

        return dfs(right,m);

     }
    int LastRemaining_Solution(int n, int m) {
        // write code here
        vector<int> nums;
        for(int i=0;i<n;i++){
            nums.push_back(i);
        }
        return dfs(nums,m);
    }
};

JZ75 字符流中第一个不重复的字符

class Solution
{
    vector<char> m_v;
    map <char,int> my_map ; //保存每个字母出现的次数
public:
  //Insert one char from stringstream
    void Insert(char ch) 
    {
        if(my_map.count(ch)==0)
        {
             m_v.push_back(ch);
        }
             my_map[ch]++;
            
        
         
    }
  //return the first appearence once char in current stringstream
    char FirstAppearingOnce() {
        for(char c:m_v)
        {
            if(my_map[c]==1)
            {
                return c;
            }
        }
        
        return '#';
    }

};

JZ14 剪绳子

#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 
     * @return int整型
     */
    int cutRope(int n) {
        // write code here
        vector<int> dp(n+1,0);
        dp[1]=1;
        dp[2]=1;
        for(int i=2;i<=n;i++){
            for(int j=1;j<=i/2;j++){
                dp[i]=max({dp[i],dp[i-j]*j,(i-j)*j});
            }
        }
        return dp[n];

    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值