Data structure: linked list, queue, stack
JZ24 reverse linked list
Niuke network link
Difficulty: simple
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* ReverseList(ListNode* pHead) { //The initialization part (initialization pointer p,pre, etc.) sometimes needs to initialize q, pNext ListNode*p=pHead; //The base pointer p starts with the first element ListNode*pre=nullptr; //pre is naturally initialized to nullptr ListNode*pNext=nullptr; while(p!=nullptr)//Traversal condition part { //Operation part pNext=p->next; p->next=pre; //Traversal iteration part pre=p; p=pNext; } return pre; } };
Linked list is one of the basic data structures - linear list, and the other is sequential list. Common arrays and strings of all kinds of data are sequential lists. Therefore, the sequence table will not be specially investigated.
General solution of simple linked list problem
As shown in the above code, a simple linked list problem solving method often includes only one traversal of a single linked list. This traversal can complete the operations required by many problems (printing, inversion, summation, deletion, search, etc.)
The code template is as follows:
It is divided into initialization part and traversal part (the traversal condition and iteration part need not be higher)
Obviously, just changing the initialization and operation parts is enough
//The initialization part (initialization pointer p,pre, etc.) sometimes needs to initialize q, pNext ListNode*p=pHead; //The base pointer p starts with the first element ListNode*pre=nullptr; //pre is naturally initialized to nullptr Other pointer initialization (if necessary) while(p!=nullptr)//Traversal condition part { //Operation part adopt p,pre Wait for the pointer to perform operations on the linked list //Traversal iteration part pre=p; p=pNext; } //Now p=nullptr, pre
Data structure: graph theory, tree
JZ82 binary tree and path with a certain value (I)
Niuke network link
Difficulty: simple
Topic: given a binary tree root and a value sum, judge whether there is a path where the sum of node values from the root node to the leaf node is equal to sum.
1. The problem path is defined as the node from the root node of the tree to the leaf node
2. Leaf nodes refer to nodes without child nodes
3. The path can only be from parent node to child node, not from child node to parent node
4. The total number of nodes is n
class Solution { public: /** * * @param root TreeNode class * @param sum int integer * @return bool Boolean */ bool hasPathSum(TreeNode* root, int sum) { //The idea of traversal with rLR if(root==nullptr)return false; return(rLR_path(root,sum,0)); // write code here } bool rLR_path(TreeNode* root, int sum, int path_val) { if(root==nullptr)return false; path_val+=root->val; if(path_val==sum&&root->left==nullptr &&root->right==nullptr)return true; else return rLR_path(root->left,sum,path_val)|| rLR_path(root->right,sum,path_val); } };
Idea: rRL traversal is enough (in fact, all four traversal methods are OK). Judge whether the current node is the root node and has accumulated just the right path length, otherwise continue to scan downward
Like the linked list problem, the simple data structure problem solution is a slight modification of the basic traversal algorithm
There are four traversal methods of binary tree: rLR, LrR, LRr and hierarchical traversal
PS: further optimization method: pruning algorithm. If the above termination conditions are not met and the current accumulated path length exceeds sum, it will directly return false and will not traverse the children of this node
Because the current problem solution has been passed, there is no further optimization
JZ34 binary tree and path with a certain value (2)
Compared with JZ82, the difficulty is further improved. It is required to return all qualified paths in the form of vector. It is necessary to use stack operations (push, pop) to backtrack, so as to verify and store feasible paths
That is, DFS with memory / DFs under global variables
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: vector<vector<int>> FindPath(TreeNode* root,int expectNumber) { if(root==nullptr)return{}; vector<vector<int>> all_path={}; CollectPath(root,expectNumber,all_path,{});//DFS from root return all_path; } //DFS function part: DFS with memory void CollectPath(TreeNode* root,int s, vector<vector<int>>& all_path,vector<int> path) { //First access the node itself if(root==nullptr)return; path.push_back(root->val); if(root->left==nullptr&&root->right==nullptr &&root->val==s) {all_path.push_back(path);//Storage feasible path return; } //Then access the left and right child nodes CollectPath(root->left, s-root->val, all_path, path); CollectPath(root->right, s-root->val, all_path, path); //Backtracking operation (when it is required to output all feasible paths of a single node, backtracking is required to verify - record nodes, that is, when DFS is required, backtracking is used to discard the "impassable" nodes) path.pop_back(); } };
Important: for binary trees, the most commonly used DFS method is rLR + backtracking (stack). The stack (vector) used for backtracking can be a global variable or a formal parameter (reference type should be used)
The general method of problem solving is:
Access the node itself, check the return condition - (no return) - > recursive call, access the left and right child nodes - (no return) - > backtracking (bounce stack)