day9 10-牛客67道剑指offer-JZ66、19、20、75、23、76、8、28、77、78

news2024/11/23 12:48:29

文章目录

  • 1. JZ66 构建乘积数组
    • 暴力解法
    • 双向遍历
  • 2. JZ19 正则表达式匹配
  • 3. JZ20 表示数值的字符串
    • 有限状态机
    • 遍历
  • 4. JZ75 字符流中第一个不重复的字符
  • 5. JZ23 链表中环的入口结点
    • 快慢指针
    • 哈希表
  • 6. JZ76 删除链表中重复的结点
    • 快慢指针
    • 三指针
    • 如果只保留一个重复结点
  • 7. JZ8 二叉树的下一个结点
    • 数组保存结点
    • 直接查找 分类讨论
  • 8. JZ28 对称的二叉树
  • 9. JZ77 按之字形顺序打印二叉树
    • 栈实现
    • 队列实现
  • 10. JZ78 把二叉树打印成多行

1. JZ66 构建乘积数组

在这里插入图片描述

暴力解法

class Solution {
public:
    vector<int> multiply(vector<int>& A) {
        // write code here
        vector<int> result(A.size(), 0);
        int flag, res, index = 0;

        while(index < result.size())
        {
            flag = A[index];
            res = 1;
            //cout << "flag = " << flag << endl;
            for(int i=0; i<A.size(); i++)
            {
                if(A[i] == flag && i==index) continue;
                res *= A[i];
            }
            result[index] = res;
            index++;
        }
        return result;
    }
};

双向遍历

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    vector<int> multiply(vector<int>& A) {
        //双向遍历
        int len = A.size();
        vector<int> result(len, 1);
        int cur = 1;
        //先乘左边,从左到右
        for(int i=1; i<A.size(); i++)
        {
            //每多一位由数组B左边的元素多乘一个前面A的元素
            result[i] = result[i-1] * A[i - 1];//cur *= A[i];result[i] = cur;
        }
        //再乘右边,从右到左
        for(int i=len-1; i>=0; i--)
        {
            result[i] *= cur;//左右两边都乘起来
            cur *= A[i];//cur为右边的累乘
        }
        return result;
    }
};

2. JZ19 正则表达式匹配

在这里插入图片描述
在这里插入图片描述
好难啊,我真的服了,搬运K神题解

  1. 解题思路:
    在这里插入图片描述
    初始化
    在这里插入图片描述
    初始化首行
    在这里插入图片描述
    dp数组更新
    在这里插入图片描述
class Solution {
public:
    bool isMatch(string s, string p) {
        //1.dp定义 s前i个字符和p前j个字符都匹配 不包括i、j
        int m = s.size()+1, n = p.size()+1;
        vector<vector<bool>> dp(m, vector<bool>(n, false));

        //2.初始化
        dp[0][0] = true;//两个字符串都为空
        for(int j=2; j<n; j+=2)//s空 p不空
            dp[0][j] = dp[0][j-2] && p[j-1]=='*';//如果j-1是* 看j-2的匹配状态
        
        //3.更新dp
        /*
        for(int i=1; i<m; i++)
        {
            for(int j=1; j<n; j++)
            {
                dp[i][j] = p[j-1] == '*' ?
                    dp[i][j-2] || dp[i-1][j] && (s[i-1] == p[j-2] || p[j-2] == '.') :
                    dp[i-1][j-1] && (p[j-1]=='.' || s[i-1]==p[j-1]);
            }
        }*/
        for(int i=1; i<m; i++)
        {
            for(int j=1; j<n; j++)
            {
                if(p[j-1] == '*')
                {
                    if(dp[i][j-2]) dp[i][j] = true;// *可以为0,所以aa和aab*中 *前前一个字符匹配,就可以匹配
                    // 此时看不加s串最后一个字母,能不能匹配到这个位置,如果能的话,
	                // 再看 * 前面的字母和s串新加的这个字母一样不,如果一样,就能匹配,如果不一样,因为此时s串多了一个字母,
	                // 就无法跟现在的 p 进行匹配了;例如:从 aa 可以匹配 aab* ,但是 aaa 匹配到 aab* 的时候,dp[i - 1][j]为true,
               		// 但是s[i - 1] 与 p[j - 2]不一样,就无法匹配;
                    else if(dp[i-1][j] && s[i-1]==p[j-2]) dp[i][j] = true;// 但是,如果 * 的前一个字符是万能的 . ,即可匹配;
                    else if(dp[i-1][j] && p[j-2]=='.') dp[i][j] = true;
                }
                else
                {
                	// 不是 * 的情况下,新加的两个字符相同,则可以继续匹配
                    if(dp[i-1][j-1] && s[i-1]==p[j-1]) dp[i][j] = true;
                    // 新加的字符不同,但是 p 中新加的是万能的 . ,就能随便匹配;
                    else if(dp[i-1][j-1] && p[j-1]=='.') dp[i][j] = true;
                }
            }
        }
        return dp[m-1][n-1];        
    }
};

3. JZ20 表示数值的字符串

在这里插入图片描述
无语了,又很难的样子,搬运力扣K神的题解了。

有限状态机

  1. 解题思路:
    本题使用有限状态自动机。根据字符类型和合法数值的特点,先定义状态,再画出状态转移图,最后编写代码即可。

  2. 字符类型:
    空格:「 」、数字:「 0—90—90—9 」、正负号:「 +−±+− 」、小数点:「 … 」、幂符号:「 eEeEeE 」。

  3. 状态定义:
    按照字符串从左到右的顺序,定义以下 9 种状态。

    • 0 开始的空格
    • 1 幂符号前的正负号
    • 2 小数点前的数字
    • 3 小数点、小数点后的数字
    • 4 当小数点前为空格时,小数点、小数点后的数字
    • 5 幂符号
    • 6 幂符号后的正负号
    • 7 幂符号后的数字
    • 8 结尾的空格
  4. 结束状态,合法的结束状态有 2, 3, 7, 8 。
    在这里插入图片描述
    在这里插入图片描述

class Solution {
public:
    bool isNumber(string s) {
        //2.有限状态机
        unordered_map<State, unordered_map<CharType, State>> transfer
        {
            {   STATE_INTITIAL, //初始状态
                {
                    {CHAR_SPACE, STATE_INTITIAL},
                    {CHAR_NUMBER, STATE_INTEGER}, 
                    {CHAR_POINT, STATE_DOT_WITHOUT_INT}, 
                    {CHAR_SIGN, STATE_INT_SIGN}
                } 
            },
            {   STATE_INT_SIGN,
                {
                    {CHAR_NUMBER, STATE_INTEGER}, 
                    {CHAR_POINT, STATE_DOT_WITHOUT_INT}
                } 
            },
            {   STATE_INTEGER,
                {
                    {CHAR_NUMBER, STATE_INTEGER},
                    {CHAR_EXP, STATE_EXP},
                    {CHAR_POINT, STATE_DOT},
                    {CHAR_SPACE, STATE_END}
                }
            },
            {   STATE_DOT,
                {
                    {CHAR_NUMBER, STATE_FRACTION},
                    {CHAR_EXP, STATE_EXP}, 
                    {CHAR_SPACE, STATE_END}
                }
            },
            {
                STATE_DOT_WITHOUT_INT, {
                    {CHAR_NUMBER, STATE_FRACTION}
                }
            }, 
            {
                STATE_FRACTION,
                {
                    {CHAR_NUMBER, STATE_FRACTION},
                    {CHAR_EXP, STATE_EXP},
                    {CHAR_SPACE, STATE_END}
                }
            }, 
            {
                STATE_EXP,
                {
                    {CHAR_NUMBER, STATE_EXP_NUMBER},
                    {CHAR_SIGN, STATE_EXP_SIGN}
                }
            }, 
            {
                STATE_EXP_SIGN, {
                    {CHAR_NUMBER, STATE_EXP_NUMBER}
                }
            }, 
            {
                STATE_EXP_NUMBER, {
                    {CHAR_NUMBER, STATE_EXP_NUMBER},
                    {CHAR_SPACE, STATE_END}
                }
            }, 
            {
                STATE_END, {
                    {CHAR_SPACE, STATE_END}
                }
            }
        };
        int len = s.size();
        State st = STATE_INTITIAL;

        for(int i=0; i<len; i++)
        {
            CharType typ = toCharType(s[i]);
            if(transfer[st].find(typ) == transfer[st].end()) return false;
            else st = transfer[st][typ];
        }
        return st == STATE_INTEGER || st==STATE_DOT || st==STATE_FRACTION || st==STATE_EXP_NUMBER || st==STATE_END;
    }
    enum State
    {
        STATE_INTITIAL,
        STATE_INT_SIGN,
        STATE_INTEGER,
        STATE_DOT,
        STATE_DOT_WITHOUT_INT,
        STATE_FRACTION,
        STATE_EXP,
        STATE_EXP_SIGN,
        STATE_EXP_NUMBER,
        STATE_END
    };
    enum CharType {
        CHAR_NUMBER,
        CHAR_EXP,
        CHAR_POINT,
        CHAR_SIGN,
        CHAR_SPACE,
        CHAR_ILLEGAL
    };

    CharType toCharType(char ch) {
        if (ch >= '0' && ch <= '9') {
            return CHAR_NUMBER;
        } else if (ch == 'e' || ch == 'E') {
            return CHAR_EXP;
        } else if (ch == '.') {
            return CHAR_POINT;
        } else if (ch == '+' || ch == '-') {
            return CHAR_SIGN;
        } else if (ch == ' ') {
            return CHAR_SPACE;
        } else {
            return CHAR_ILLEGAL;
        }
    }
};

遍历

小天才才的题解
在这里插入图片描述

class Solution {
public:
    bool isNumber(string s) {
        //1. 遍历 找到所有合法情况
        int i = 0, j = s.size() - 1;
        //找到字符串中第一个不为空的位置
        for(; i<s.size(); i++)
        {
            if(s[i] != ' ') break;
        }
        //从末尾找到字符串最后一个不为空的位置
        for(; j>=0; j--)
        {
            if(s[j] != ' ') break;
        }
        //判断是否为数值,以及是否有小数点和e/E
        bool numFlag = false;
        bool dotFlag = false;
        bool eFlag = false;
        for(int k=i; k<=j; k++)
        {
            //判断是否为数字
            //if(isdigit(s[k])) numFlag=true;
            if(s[k] >= '0' && s[k] <= '9') numFlag = true;
            //判断是否为小数点,并且之前是否出现过小数点和e/E
            else if(s[k]=='.' && !dotFlag && !eFlag) dotFlag = true;//是小数点 且之前没有出现过小数点和e/E
            //判断是否为e/E,并且之前是否出现过e/E和数字
            else if((s[k]=='e' || s[k]=='E') && !eFlag && numFlag)//是e/E 之前没有出现过e/E 且e/E 前后是数字
            {
                eFlag = true;
                //因为e/E的前后必须都是数字,所以如果找到了e/E就把num_flag设为false,
                //遇到下一个数字再设为true,避免出现12e的情况
                numFlag = false;
            }
            //判断是否为+-,并且符号是否在数值的首位,或者前一位是e/E
            else if((s[k]=='+' || s[k]=='-') && (k==i || s[k-1]=='e' || s[k-1]=='E')) continue;//在数值的首位或者前一位是e/E
            else return false;//其他均为非法情况,输出false
        }
        return numFlag;//肯定有数字
    }
};

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

在这里插入图片描述

class Solution
{
public:
  //Insert one char from stringstream
    void Insert(char ch) {
        v.push_back(ch);
        result[ch]++;//统计次数
    }
  //return the first appearence once char in current stringstream
    char FirstAppearingOnce() {
        for(int i=0; i<v.size(); i++)
        {
            if(result[v[i]] == 1) return v[i];
        }
        return '#';
    }
    vector<char> v;
    unordered_map<char, int> result;
};

5. JZ23 链表中环的入口结点

在这里插入图片描述

快慢指针

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        if(pHead == nullptr || pHead->next == nullptr) return nullptr;
        ListNode* fast = pHead, *slow = pHead;
        //写法1
        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
            if(fast == slow)//第一次相遇
            {
                slow = pHead;
                while(slow != fast)
                {
                    slow = slow->next;
                    fast = fast->next;
                }
                return fast;
            }
        }
        return nullptr;
    }
};
  • 写法2
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        if(pHead == nullptr || pHead->next == nullptr) return nullptr;
        ListNode* fast = pHead, *slow = pHead;
        //写法2
        while(fast!=nullptr && fast->next!=nullptr)
        {
            slow = slow->next;
            fast = fast->next->next;
            if(slow == fast) break;//不应该直接返回 要做判断 return fast->next;
            //cout << slow->val << fast->val<<endl;
        }
        // 若是快指针指向null,则不存在环
        if(fast==nullptr || fast->next==nullptr) return nullptr;
        //此时fast在环入口 让slow从头出发 同时走
        slow = pHead;//再次相遇就是环入口
        while (fast != slow) 
        {
            fast = fast->next;
            slow = slow->next;
        }
        return fast;
    }
};

哈希表

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead) {
        if(pHead == nullptr || pHead->next == nullptr) return nullptr;
        //哈希表
        unordered_set<ListNode*> hashset;
        while (pHead) 
        {
            if(hashset.count(pHead)) return pHead;
            hashset.insert(pHead);
            pHead = pHead->next;
        }
        return nullptr;
    }
};

6. JZ76 删除链表中重复的结点

在这里插入图片描述

快慢指针

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead) {
        if (!pHead) return NULL;
        ListNode* slow = new ListNode(-1), *fast = new ListNode(-1), *dummy = new ListNode(-1);
        dummy->next = pHead;
        // 初始化两个指针
        slow = dummy;
        fast = dummy->next;
        while(fast)
        {
            while(fast->next && fast->val == fast->next->val)// 遇到重复
                fast = fast->next;
            cout << "fast " << fast->val <<endl;
            cout << "slow " << slow->val <<endl;
            if(slow->next != fast)// 此时slow连接的还是fast的重复结点 需要删除结点
            {
                slow->next = fast->next;
                fast = fast->next;
            }
            else// 没有重复
            {
                fast = fast->next;
                slow = slow->next;
            }
        }
        return dummy->next;
    }
};

三指针

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead) {
        if (!pHead) return NULL;
        //三指针
        ListNode* pre = new ListNode(-1), *cur = new ListNode(-1), *dummyhead = new ListNode(-1);
        dummyhead->next = pHead;
        cur = pHead;//遍历链表 判断是否有重复
        pre = dummyhead;//虚拟链表尾
        while(cur)
        {
            if(cur->next!=nullptr && cur->val == cur->next->val)
            {
                while(cur->next!=nullptr && cur->val == cur->next->val)
                    cur = cur->next;
                //此时没有重复了
                pre->next = cur->next;
                cur = cur->next;
            }
            else
            {
                cur = cur->next;
                pre = pre->next;
            }
        }
        return dummyhead->next;
    }
};

如果只保留一个重复结点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->3->4->5

ListNode* deleteDuplication(ListNode* pHead)
{
    if (pHead == nullptr) return nullptr;
    ListNode* node = (ListNode*)malloc(sizeof(struct ListNode));
    node = pHead;
    while (node != nullptr) {

        if (node->next!=nullptr && node->val == node->next->val) {//这里千万要判断node->next也不为空才可以
            while (node->next != nullptr && node->val == node->next->val) {
                node->next = node->next->next;
            }
        }
        node = node->next;
    }
    return pHead;
}
  • 写法2
ListNode* deleteDuplication(ListNode* pHead)
{
	if (pHead == nullptr || pHead->next == nullptr) return pHead;
	ListNode dummpyHead(0);
	dummpyHead.next = pHead;
	ListNode* pre = &dummpyHead;
	ListNode* cur = dummpyHead.next;
	while (cur != nullptr) {
		if (cur->next != nullptr && cur->val == cur->next->val) {
			while (cur->next != nullptr && cur->val == cur->next->val)
			{
				cur = cur->next;
			}
			pre->next = cur;//删除重复结点
			pre = pre->next;
			cur = cur->next;
		}
		else {
			pre = pre->next;
			cur = cur->next;
		}

	}
	return dummpyHead->next;
}

7. JZ8 二叉树的下一个结点


在这里插入图片描述

数组保存结点

中序遍历,保存节点在数组中,再匹配目标节点

/*
struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
        
    }
};
*/
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode) {
        if(pNode == nullptr) return nullptr;
        vector<TreeLinkNode*> v;
        //1.获取根节点
        TreeLinkNode* root = pNode;
        while(root->next != nullptr) root = root->next;

        //2.保存节点
        inOrder(root, v);

        //3.匹配目标节点
        for(int i=0; i<v.size(); i++)
        {
            if(pNode == v[i]) return v[i+1];
        }
        return nullptr;
    }
    void inOrder(TreeLinkNode* root, vector<TreeLinkNode*>& v)
    {
        if(root == nullptr) return;
        if(root->left) inOrder(root->left, v);
        v.push_back(root);
        if(root->right) inOrder(root->right, v);
    }
};

直接查找 分类讨论

默认当前节点作为根节点,那么中序遍历的下一个节点应该是其右子节点,如果
有右子树
有左子树,中序遍历的下一个节点
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 写法1
/*
struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
    }
};
*/
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode) {
        if(pNode == nullptr) return nullptr;
        //分类
        // 如果有右子树
        TreeLinkNode* cur = nullptr;
        if(pNode->right != nullptr)
        {
            pNode = pNode->right;
            // 一直找到右子树的最左下的结点为返回值
            while(pNode->left != nullptr) pNode = pNode->left;
            return pNode;
        }
        //如果有父节点 先看有没左子节点 有就返回;没有,说明当前节点是右叶子节点 只有右子节点 一直往上找父节点
        while(pNode->next != nullptr)
        {
            cur = pNode->next;//当前结点的父节点
            if(cur->left == pNode) return cur;//无右子树 直到当前结点是其父节点的左子结点 返回
            pNode = pNode->next;
        }
        return nullptr;
    }
};
  • 写法2
/*
struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) { 
    }
};
*/
#include <unistd.h>
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode) {
        if(pNode == nullptr) return nullptr;
        //分类 写法2
        TreeLinkNode* node = nullptr;
        if(pNode->right != nullptr)//如果当前节点有右子树,则右子树最左边的那个节点就是
        {
            node = pNode->right;
            while(node->left != nullptr) node = node->left;
            return node;
        }
        node = pNode;
        while(node->next != nullptr && node == node->next->right)//当前节点有右子树
        {
            node = node->next;//找到当前节点是其父亲节点的左孩子的那个节点,然后返回其父亲节点 相当于一直往上找父节点
        }
        return node->next;//如果当前节点没有右子树 有左子树 返回当前节点的父节点
    }
};
  • 写法3
/*
struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
    }
};
*/
#include <unistd.h>
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode) {
        if(pNode == nullptr) return nullptr;
        //分类 写法3
        TreeLinkNode* cur = nullptr;

        if(pNode->right)// 如果有右子树 一直找到右子树的最左下的结点为返回值
        {
            cur = pNode->right;
            while(cur->left != nullptr) cur = cur->left;
            return cur;
        }
        // 如果无右子树 且当前结点是其父节点的左子结点
        if(pNode->next != nullptr && pNode == pNode->next->left)
            return pNode->next;// 返回当前结点的父节点
        // 如果无右子树 且当前结点是其父节点的右子节点
        if(pNode->next != nullptr)
        {
            cur = pNode->next;
            // 沿着左上一直爬树,爬到当前结点是其父节点的左自己结点为止
            while(cur->next != nullptr && cur == cur->next->right) cur = cur->next;
            return cur->next;// 返回当前结点的父节点
        }
        return nullptr;

    }
};

8. JZ28 对称的二叉树

在这里插入图片描述

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    bool isSymmetrical(TreeNode* pRoot) {
        if(pRoot == nullptr) return true;
        return dfs(pRoot->left, pRoot->right);
    }
    bool dfs(TreeNode* node1, TreeNode* node2)
    {
        if(node1 == nullptr && node2 == nullptr) return true;
        if(node1 == nullptr || node2 == nullptr) return false;
        if(node1->val != node2->val) return false;
        return dfs(node1->left, node2->right) && dfs(node1->right, node2->left);
    }
};

9. JZ77 按之字形顺序打印二叉树

在这里插入图片描述

栈实现

在这里插入图片描述

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int>> result;
        if(pRoot == nullptr) return result;
        stack<TreeNode*> st1;//保存从右向左节点
        stack<TreeNode*> st2;//保存从左向右节点
        st1.push(pRoot);
        while(!st1.empty() || !st2.empty())
        {
            vector<int> temp;
            TreeNode* cur;
            if(!st1.empty())
            {
                while(!st1.empty())
                {
                    cur = st1.top();//访问st1节点后 从左向右存入st2
                    temp.push_back(cur->val);//当前层的节点
                    if(cur->left) st2.push(cur->left);
                    if(cur->right) st2.push(cur->right);
                    st1.pop();
                }
                result.push_back(temp);
            }
            temp.clear();
            if(!st2.empty()) 
            {
                while (!st2.empty()) 
                {
                    cur = st2.top();
                    temp.push_back(cur->val);
                    if(cur->right) st1.push(cur->right);
                    if(cur->left) st1.push(cur->left);
                    st2.pop();
                }
                result.push_back(temp);
            }
        }
        return result;
    }
};

队列实现

在这里插入图片描述

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
#include <vector>
class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int>> result;
        if(pRoot == nullptr) return result;
        //队列实现
        queue<TreeNode*> que;
        que.push(pRoot);
        int level = 0, size = 0;
        //TreeNode* cur = nullptr;
        while(!que.empty())
        {
            vector<int> temp;//存储每一行结果
            size = que.size();// 当前队列长度 否则后面会更新
            for(int i=0; i<size; i++)
            {
                TreeNode* cur = que.front();
                que.pop();
                if(cur == nullptr) continue; // 空元素跳过
                que.push(cur->left); // 左孩子入队列
                que.push(cur->right); // 右孩子入队列
                //第一层从左向右 level从0开始 level为偶数 左到右;下一层从右向左 level为奇数 右到左
                if(level % 2 == 0) temp.push_back(cur->val);// 从左至右打印
                else temp.insert(temp.begin(), cur->val);// 从右至左打印
            }
            level++;
            if(!temp.empty()) result.push_back(temp);
        }
        return result;
    }
};

10. JZ78 把二叉树打印成多行

在这里插入图片描述

队列+迭代,和上面那道题有点像,简单一点

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int>> result;
        if(pRoot == nullptr) return result;
        //队列
        queue<TreeNode*> que;
        que.push(pRoot);
        vector<int> v;
        TreeNode* cur;
        int size = 0;
        while(!que.empty())
        {
            v.clear();
            size = que.size();
            for(int i=0; i<size; i++)
            {
                cur = que.front();
                que.pop();
                v.push_back(cur->val);
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
            result.push_back(v);
        }
        return result;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/871553.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HttpRunner自动化工具之设置代理和请求证书验证

httprunner设置代理&#xff1a; httprunner 库本身没有提供设置代理的接口&#xff0c;但是底层使用了urllib.requests 等库&#xff0c;可以设置HTTP_PROXY 和HTTPS_PROXY 环境变量&#xff0c;常用的网络库会自动识别这些环境变量。 日常调试使用代理&#xff08;如charles…

SQL-每日一题【】

题目 Employees 表&#xff1a; EmployeeUNI 表&#xff1a; 展示每位用户的 唯一标识码&#xff08;unique ID &#xff09;&#xff1b;如果某位员工没有唯一标识码&#xff0c;使用 null 填充即可。 你可以以 任意 顺序返回结果表。 返回结果的格式如下例所示。 示例 1&a…

使用ip2region获取客户端地区

目录 从gitee拉取ip2region.xdb资源文件 写测试类 注意要写对资源路径 本地测试结果 ​编辑 远端测试结果 从gitee拉取ip2region.xdb资源文件 git clone https://gitee.com/lionsoul/ip2region.git 将xdb放入resources资源文件夹 写测试类 private Searcher searcher;GetMap…

funbox3靶场渗透笔记

funbox3靶场渗透笔记 靶机地址 https://download.vulnhub.com/funbox/Funbox3.ova 信息收集 fscan找主机ip192.168.177.199 .\fscan64.exe -h 192.168.177.0/24___ _/ _ \ ___ ___ _ __ __ _ ___| | __/ /_\/____/ __|/ __| __/ _ |/ …

数据结构-栈的实现(C语言版)

前言 栈是一种特殊的线性表&#xff0c;只允许在固定的一端进行插入和删除的操作&#xff0c;进行数据插入和删除的一端叫做栈顶&#xff0c;另一端叫做栈底。 栈中的数据元素遵循后进先出的的原则。 目录 1.压栈和出栈 2. 栈的实现 3.测试代码 1.压栈和出栈 压栈&#xff…

最小生成树 — Prim算法

同Kruskal算法一样&#xff0c;Prim算法也是最小生成树的算法&#xff0c;但与Kruskal算法有较大的差别。 Prim算法整体是通过“解锁” “选中”的方式&#xff0c;点 -> 边 -> 点 -> 边。 因为是最小生成树&#xff0c;所以针对的也是无向图&#xff0c;所以可以随意…

带你了解SpringBoot支持的复杂参数--自定义对象参数-自动封装

&#x1f600;前言 本篇博文是关于SpringBoot 在响应客户端请求时支持的复杂参数和自定义对象参数&#xff0c;希望您能够喜欢&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章…

Docker知识(详细笔记)

概览图 文章目录 概览图docker 知识速查1. 初识 Docker1.1 概念1.2 特点1.3 架构1.4 应用场景1.5 安装 Docker1.6 配置 Docker 镜像 2. Docker 命令2.1 Docker 进程相关命令2.2 Docker 镜像相关命令2.3 Docker 容器相关命令 3. Docker 容器的数据卷3.1 数据卷概念及作用3.1.1 概…

小米平板6Max14即将发布:自研G1 电池管理芯片,支持33W反向快充

明天晚上7点&#xff08;8 月 14 日&#xff09;&#xff0c;雷军将进行年度演讲&#xff0c;重点探讨“成长”主题。与此同时&#xff0c;小米将推出一系列全新产品&#xff0c;其中包括备受瞩目的小米MIX Fold 3折叠屏手机和小米平板6 Max 14。近期&#xff0c;小米官方一直在…

java 9新特效解读(4)

目录 InputStream 加强 增强的 Stream API takeWhile()的使用 dropWhile()的使用 ofNullable()的使用 iterate()重载的使用 Optional获取Stream的方法 Optional类中stream()的使用 javascript引擎升级&#xff1a;Nashorn InputStream 加强 InputStream 终于有了…

supervisor因为依赖安装失败的解决方法

安装FEATA时报错情况 下列软件包有未满足的依赖关系&#xff1a;supervisor : 依赖: python-pkg-resources 但是它将不会被安装依赖: python-meld3 但是它将不会被安装依赖: python:any (< 2.8)依赖: python:any (> 2.7.5-5~) E: 无法修正错误&#xff0c;因为您要求某些…

图书管理系统-Java

目录 一、图书管理系统样式 二、图书管理系统具体实现 2.1 book包 2.2 user包 2.3 Main类 2.4 operation包 一、图书管理系统样式 管理系统效果图&#xff1a; 通过效果图我们可以看到&#xff0c;首先要实现登录&#xff0c;得到用户姓名和身份&#xff0c;依据用户的身份不…

Java代理模式——静态代理与动态代理

代理模式 代理模式允许你为其他对象提供一个代理&#xff0c;以控制对这个对象的访问。代理模式在不改变实际对象的情况下&#xff0c;可以在访问对象时添加额外的功能。 可以理解为代理模式为被代理对象创造了一个替身&#xff0c;调用者可以通过这个替身去实现这个被代理对…

网络基础——网络的由来与发展史

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、网络的由来 二、计算机网络的发展史 1、第一阶段 2、第二阶段 3、第三阶段 前言 每天都是使用网络&#xff0c;那么你知道网络…

【C++起飞之路】初级—— auto、范围for循环、宏函数和内联函数

auto、范围for、内联函数、宏函数和nullptr 一、auto — 类型推导的魔法&#xff08;C 11)1、auto 是什么&#xff1f;2、工作原理3、优势4、限制和注意事项 二、范围for (C11)1、基本语法2、优势3、工作原理4、注意事项5、C11&#xff1a; 范围 for 循环的扩展&#xff1a; 三…

阿里云免费服务器领取入口_限制条件_申请指南

阿里云免费服务器领取&#xff0c;个人和企业用户均可以申请&#xff0c;个人免费服务器1核2GB 每月750小时&#xff0c;企业u1服务器2核8GB免费使用3个月&#xff0c;阿里云百科分享阿里云免费服务器申请入口、个人和企业免费配置、申请资格条件及云服务器免费使用时长&#x…

使用 HTML、CSS 和 JavaScript 创建多步骤表单

使用 HTML、CSS 和 JavaScript 创建多步骤表单 为了处理又长又复杂的表单&#xff0c;我们需要将它们分成多个步骤。通过一次只在屏幕上显示一些输入&#xff0c;表单会感觉更容易理解&#xff0c;并防止用户感到被大量的表单字段淹没。 在本文中&#xff0c;我将逐步指导如何…

HTML详解连载(5)

HTML详解连载&#xff08;5&#xff09; 专栏链接 [link](http://t.csdn.cn/xF0H3)下面进行专栏介绍 开始喽行高&#xff1a;设置多行文本的间距属性名属性值行高的测量方法 行高-垂直居中技巧 字体族属性名属性值示例扩展 font 复合属性使用场景复合属性示例注意 文本缩进属性…

全网最细,Python接口自动化测试-Session会话保持(实战详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 在接口测试的过程…

ubuntu python虚拟环境venv搭配systemd服务实战(禁用缓存下载--no-cache-dir)

文章目录 参考文章目录结构步骤安装venv查看python版本创建虚拟环境激活虚拟环境运行我们程序看缺少哪些依赖库&#xff0c;依次安装它们接下来我们配置python程序启动脚本&#xff0c;脚本中启动python程序前需先激活虚拟环境配置.service文件然后执行部署脚本&#xff0c;成功…