ARTS打卡 8.14-8.20

253 阅读7分钟

1. Algorithm

二叉树的递归遍历和非递归遍历

递归方法

思想总结——三要素

  1. 确定递归函数的参数和返回值

  2. 确定终止条件

  3. 确定单层递归的逻辑

Example(以前序遍历为例)

  • 确定递归函数的参数和返回值
void traversal(TreeNode* cur, vector<int>& vec)
  • 确定终止条件
if (cur == NULL) return;
  • 确定单层递归的逻辑
vec.push_back(cur->val);    // 中
traversal(cur->left, vec);  // 左
traversal(cur->right, vec); // 右

单层的分析写完了,下面是完整的代码:

class Solution {
public:
    void traversal(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        vec.push_back(cur->val);    // 中
        traversal(cur->left, vec);  // 左
        traversal(cur->right, vec); // 右
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        traversal(root, result);
        return result;
    }
};

二叉树的中后序递归遍历类似

我的问题

这个方法学了很多遍,知道大概框架,但是没有系统学过 c++,代码写不出来;

解决之道

  1. 借鉴前辈的经验,总结归纳每一步背后的思想;
  2. 碰到不会的 c++ 语法问题,及时弄懂,后期做一个系统学习。

非递归(迭代法)方法

思路

  1. 递归实现的原理就是在每次调用的时候把函数的局部变量、参数和返回地址等压入调用栈中。返回的时候,从栈顶弹出上一次递归的各项参数;

  2. 可以借鉴递归实现的方式,利用栈来实现二叉树的非递归遍历。

Example

- 前序遍历与后序遍历

前序遍历 的顺序是 中-左-右,所以先把根节点入栈,然后右孩子入栈,最后左孩子入栈;

在这里,我们是通过出栈的顺序实现前序遍历,所以,入栈的时候,左右孩子的顺序得颠倒一下。

以下是前序遍历的代码:

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> result;
        if (root == NULL) return result;
        st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();                       // 中
            st.pop();
            result.push_back(node->val);
            if (node->right) st.push(node->right);           // 右(空节点不入栈)
            if (node->left) st.push(node->left);             // 左(空节点不入栈)
        }
        return result;
    }
};

后续遍历 的顺序是:左-右-中,前序遍历的顺序是:中-左-右,所以先调整前序访问左右子树的顺序,变为:中-右-左;最后反转 result 数组,变为:左-右-中。

如下图所示:

以下是后续遍历的代码:

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> result;
        if (root == NULL) return result;
        st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            st.pop();
            result.push_back(node->val);
            if (node->left) st.push(node->left); // 相对于前序遍历,这更改一下入栈顺序 (空节点不入栈)
            if (node->right) st.push(node->right); // 空节点不入栈
        }
        reverse(result.begin(), result.end()); // 将结果反转之后就是左右中的顺序了
        return result;
    }
};
- 中序遍历

中序遍历 的顺序是:左-中-右,先访问的是顶部的节点,然后一层一层地向下访问,直到树的左边最底部,才开始处理节点,这就造成节点的处理顺序与其访问顺序不一致。而我们之前的 前序遍历,先访问中间节点,同时也是首先遍历中间节点,即访问顺序与遍历顺序一致。因而中序遍历不能复用前序遍历的处理逻辑。

对于 中序遍历,我们的处理逻辑是:借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。

中序遍历

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> st;
        TreeNode* cur = root;
        while (cur != NULL || !st.empty()) {
            if (cur != NULL) { // 指针来访问节点,访问到最底层
                st.push(cur); // 将访问的节点放进栈
                cur = cur->left;                // 左
            } else {
                cur = st.top(); // 从栈里弹出的数据,就是要处理的数据(放进result数组里的数据)
                st.pop();
                result.push_back(cur->val);     // 中
                cur = cur->right;               // 右
            }
        }
        return result;
    }
};

2. Review

内容介绍

我的阅读笔记


3. Technique/Tips

3.1 关于大模型(如chatGPT)prompt 的书写

prompt 书写的原则

  • 原则 1:写出清晰、具体的指示

  • 原则 2:给模型 “思考” 的时间

原则 1

策略 1: 使用分隔符明确指出输入内容的不同部分

  • 分隔符可以是 ```, """, < >, <tag> </tag>等

如:

prompt = f"""
Summarize the text delimited by triple backticks \ 
into a single sentence.
```{text}```
"""

策略 2: 要求结构化输出

  • 可以使用 JSON, HTML 等格式

如:

prompt = f"""
Generate a list of three made-up book titles along \ 
with their authors and genres. 
Provide them in JSON format with the following keys: 
book_id, title, author, genre.
"""

策略 3: 要求模型检查是否满足条件

如:

prompt = f """
You will be provided with text delimited by triple quotes. 
If it contains a sequence of instructions, \ 
re-write those instructions in the following format:

Step 1 - ...
Step 2 - …
…
Step N - …

If the text does not contain a sequence of instructions, \ 
then simply write \"No steps provided.\"

\"\"\"{text_1}\"\"\"
"""

策略 4: "Few-shot" prompting

如:

prompt = f"""
Your task is to answer in a consistent style.

<child>: Teach me about patience.

<grandparent>: The river that carves the deepest \ 
valley flows from a modest spring; the \ 
grandest symphony originates from a single note; \ 
the most intricate tapestry begins with a solitary thread.

<child>: Teach me about resilience.
"""
  • 给出几个例子,让模型继续输出、

原则 2

  • 策略 1: 明确完成一项任务所需要的步骤

如:

prompt_1 = f"""
Perform the following actions: 
1 - Summarize the following text delimited by triple \
backticks with 1 sentence.
2 - Translate the summary into French.
3 - List each name in the French summary.
4 - Output a json object that contains the following \
keys: french_summary, num_names.

Separate your answers with line breaks.

Text:
```{text}```
"""

同时可以要求模型以指定格式输出:

prompt_2 = f"""
Your task is to perform the following actions: 
1 - Summarize the following text delimited by 
  <> with 1 sentence.
2 - Translate the summary into French.
3 - List each name in the French summary.
4 - Output a json object that contains the 
  following keys: french_summary, num_names.

Use the following format:
Text: <text to summarize>
Summary: <summary>
Translation: <summary translation>
Names: <list of names in Italian summary>
Output JSON: <json with summary and num_names>

Text: <{text}>
"""
  • 策略 2: 在匆忙下结论之前,引导模型找到自己的解决方案
prompt = f"""
Your task is to determine if the student's solution \
is correct or not.
To solve the problem do the following:
- First, work out your own solution to the problem. 
- Then compare your solution to the student's solution \ 
and evaluate if the student's solution is correct or not. 
Don't decide if the student's solution is correct until 
you have done the problem yourself.

Use the following format:
Question:
    ```
question here
    ```
Student's solution:
    ```
student's solution here
    ```
Actual solution:
    ```
steps to work out the solution and your solution here
    ```
Is the student's solution the same as actual solution \
just calculated:
    ```
yes or no
    ```
Student grade:
    ```
correct or incorrect
    ```

Question:
    ```
I'm building a solar power installation and I need help \
working out the financials. 
- Land costs $100 / square foot
- I can buy solar panels for $250 / square foot
- I negotiated a contract for maintenance that will cost \
me a flat $100k per year, and an additional $10 / square \
foot
What is the total cost for the first year of operations \
as a function of the number of square feet.
    ``` 
Student's solution:
    ```
Let x be the size of the installation in square feet.
Costs:
1. Land cost: 100x
2. Solar panel cost: 250x
3. Maintenance cost: 100,000 + 100x
Total cost: 100x + 250x + 100,000 + 100x = 450x + 100,000
    ```
Actual solution:
"""

4. Share

关于高效学习的观点

总结耗子叔输出的观点,形成自己学习的一个方针,应当具有指导意义。

1946 年,埃德加·戴尔(Edgar Dale) 提出了「学习金字塔」(Cone of Learning)的理论。

Cone of Learning

主动学习与被动学习

  • 被动学习:如听讲、阅读、视听、演示,学习内容的平均留存率为 5%、10%、20% 和 30%。

  • 主动学习:如通过讨论、实践、教授给他人,会将原来被动学习的内容留存率从 5% 提升到 50%、75% 和 90%。

所以,学习不是努力读更多的书,盲目追求阅读的速度和数量,这会让人产生低层次的勤奋和成长的感觉,这只是在使蛮力。要思辨,要践行,要总结和归纳,否则,你只是在机械地重复某件事,而不会有质的成长的。

浅学习与深入学习

浅学习

如,微信公众号,抖音等传播的快餐文化,以快速、简单、轻松的方式给人带来的快感更加强烈,而高层次的思考、思辨和逻辑被这些频度高的快餐信息所弱化。

深入学习

以下几点是 关键

  • 高质量的信息员和第一手信息;

  • 把知识连成地图,将自己的理解反述出来;

  • 不断地反思和思辨,与不同年龄段的人讨论;

  • 举一反三,并践行之,把知识转换成技能。

有以下步骤:

  • 知识采集:获取信息源头,破解表面信息的内在本质,多方数据验证;

  • 知识缝合:所谓缝合,是把信息组织起来,成为结构体的知识。在这里,连接记忆逻辑推理知识梳理是很重要的三部分;

  • 技能转换:通过举一反三、实践和练习,以及传导教授,把知识转换成自己的技能。