No. 04 - Paths with Specified Sum in Binary Tree

No. 04 - Paths with Specified Sum in Binary Tree


Question: All nodes along children pointers from root to leaf nodes form a path in a binary tree. Given a binary tree and a number, please print out all of paths where the sum of all nodes value is same as the given number. The node of binary tree is defined as:

struct BinaryTreeNode
{
     int                    m_nValue;
    BinaryTreeNode*        m_pLeft; 
    BinaryTreeNode*        m_pRight;
};

For instance, if inputs are the binary tree in Figure 1 and a number 22, two paths with be printed: One is the path contains node 10 and 12, and the other contains 10, 5 and 7.

Analysis: Path in a binary tree is a new concept for many candidates, so it is not a simple question for them. We may try to find the hidden rules with concrete examples. Let us take the binary tree in Figure 1 as an example.

Since paths always start from a root node, we traverse from a root node in a binary tree. We have three traversal orders, pre-order, in-order and post-order, and we firstly visit a root node with pre-order traversal.

According to the pre-order traversal process on the binary tree in Figure 1, we visit the node 5 after visiting the root node 10. Since a binary tree node does not have a pointer to its parent node, we do not know what nodes have been visited when we reach the node 5 if we do not save the visited node on the path. Therefore, we could insert the current node into a path when we reach it during traversal. The path contains two nodes with value 10 and 5 when we are visiting the node 5. Then we insert the node 4 into the path too when we reach it. We have reached a leaf node, and the sum of three nodes in the path is 19. Since it is not same as the input number 22, current path is not a qualified one.
We should continue to traverse other nodes. Before visiting other nodes, we should return back to the node 5, and then reach the node 7. It can be noticed that node 4 is no longer in the path from node 10 to node 7, so we should remove it from the path. When we are visiting node 7, we insert it into the path, which contains three nodes now. Since the sum of value of these three nodes is 22, the path is qualified.

Lastly we are going to visit the node 12. We should return back to node 5 then back to node 10 before we visit node 12. When we return back from a child node to its parent node, we remove the child node from the path. When we reach the node 12 eventually, the path contains two nodes, one is node 10 and the other is node 12. Since the sum of value of these two nodes is 22, the path is qualified too.

We can summarize the whole process above with the Table 1:

Step
Operation
Is it a leaf?
Path
Sum of nodes value
1
Visit node 10
No
node 10
10
2
Visit node 5
No
node 10, node 5
15
3
Visit node 4
Yes
node 10, node 5, node 4
19
4
Return to node 5

node 10, node 5
15
5
Visit node 7
Yes
node 10, node 5, node 7
22
6
Return to node 5

node 10, node 5
15
7
Return to node 10

node 10
10
8
Visit node 12
Yes
node 10, node 12
22
Table 1: The process to traverse the binary tree in Figure 1

It is time to summarize some rules with the example above. When we visit a node with pre-order traversal order, we insert it into the path, and accumulate its value to  sum.  When the node is a leaf and  sum is same as the input number, the path is qualified and we need to print it. We continue to visit its children if the current node is not a leaf. After we finish visiting the current node, a recursive function will return back to its parent node automatically, so we should remove the current node from the path before a function returns to make sure the nodes in the path is same as the path from root node to its parent node. The data structure to save paths should be a stack, because paths should be consistent to the recursion status and recursion is essentially pushing and popping in a call stack.
Here is some sample code for this problem:

void FindPath(BinaryTreeNode* pRoot,  int expectedSum)
{
     if(pRoot == NULL)
         return;

    std::vector< int> path;
     int currentSum = 0;
    FindPath(pRoot, expectedSum, path, currentSum);
}

void FindPath
(
    BinaryTreeNode*   pRoot,       
     int               expectedSum, 
    std::vector< int>& path,        
     int&              currentSum
)
{
    currentSum += pRoot->m_nValue;
    path.push_back(pRoot->m_nValue);

// Print the path is the current node is a leaf
// and the sum of all nodes value is same as expectedSum
     bool isLeaf = pRoot->m_pLeft == NULL && pRoot->m_pRight == NULL;
     if(currentSum == expectedSum && isLeaf)
    {
        printf( "A path is found: ");
        std::vector< int>::iterator iter = path.begin();
         for(; iter != path.end(); ++ iter)
            printf( "%d\t", *iter);
       
        printf( "\n");
    }

    // If it is not a leaf, continue visition its children
     if(pRoot->m_pLeft != NULL)
        FindPath(pRoot->m_pLeft, expectedSum, path, currentSum);
     if(pRoot->m_pRight != NULL)
        FindPath(pRoot->m_pRight, expectedSum, path, currentSum);

     // Before returning back to its parent, remove it from path,
    currentSum -= pRoot->m_nValue;
    path.pop_back();
}

In the code above, we save path with a vector in STL actually. We use function push_back to insert a node and pop_back to remove a node to assure it is “First in Last out” in a path. The reason we don’t utilize a stack in STL is that we can only get an element at the top of a stack, but we need to get all nodes when we print a path. Therefore, std::stack is not the best choice for us. 

The author Harry He owns all the rights of this post. If you are going to use part of or the whole of this ariticle in your blog or webpages,  please add a reference to  http://codercareer.blogspot.com/. If you are going to use it in your books, please contact me (zhedahht@gmail.com) . Thanks.

<think>好的,我现在要解决用户的问题:在Spring Boot项目中自动注入依赖失败,报错无法解析占位符'jwt.exclude-paths'。首先,我需要明确错误的原因。根据用户提供的引用内容,尤其是引用[4]中提到的JWT配置和白名单问题,可能涉及到配置属性的定义或注入方式。 首先,用户提到的错误是`IllegalArgumentException`,具体是无法解析占位符。这通常发生在Spring尝试注入一个属性值,但找不到对应的配置项。可能的原因有几个: 1. **属性未正确配置**:在`application.properties`或`application.yml`中可能没有定义`jwt.exclude-paths`属性,或者属性名拼写错误。 2. **配置类未加载**:使用`@ConfigurationProperties`或`@Value`注入时,相关配置类未被Spring扫描到,或者配置类缺少必要的注解。 3. **占位符语法错误**:在代码中使用`@Value("${jwt.exclude-paths}")`时,可能格式有误,比如缺少括号或引号。 4. **配置文件未正确加载**:可能配置文件的位置不对,或者Spring Boot没有正确加载配置文件。 接下来,我需要结合用户提供的引用内容分析。引用[1]提到Spring Boot的依赖管理和Kotlin插件的使用,但用户的问题可能与Java相关,所以暂时可能不涉及Kotlin的问题。引用[4]中用户提到在配置JWT时使用了白名单,并且遇到了拦截器配置的问题,但这里的错误是注入失败,可能和属性配置有关。 可能的解决步骤: 1. **检查配置文件**:确认`application.properties`或`application.yml`中有`jwt.exclude-paths`的定义。例如,在YAML中: ```yaml jwt: exclude-paths: /api/login,/api/refresh ``` 或者在properties文件中: ```properties jwt.exclude-paths=/api/login,/api/refresh ``` 需要确保属性名正确,没有拼写错误,并且格式正确。 2. **检查注入方式**:查看代码中使用`@Value`注入的地方是否正确。例如: ```java @Value("${jwt.exclude-paths}") private String excludePaths; ``` 确保注解的语法正确,并且变量名与占位符一致。 3. **处理多值属性**:如果`jwt.exclude-paths`是一个列表,可能需要用数组或List来接收。例如: ```java @Value("${jwt.exclude-paths}") private List<String> excludePaths; ``` 或者在配置类中使用`@ConfigurationProperties`绑定前缀: ```java @Configuration @ConfigurationProperties(prefix = "jwt") public class JwtProperties { private List<String> excludePaths; // getters and setters } ``` 然后在需要的地方注入`JwtProperties`。 4. **确保配置类被扫描**:如果使用`@ConfigurationProperties`,需要确保主应用类有`@EnableConfigurationProperties`注解,或者配置类被`@Component`扫描到。 5. **检查配置文件位置和激活的profile**:确认配置文件位于正确的位置(如`src/main/resources`),并且激活的profile对应的配置文件存在该属性。 6. **使用默认值或检查可选性**:如果属性可能不存在,可以设置默认值: ```java @Value("${jwt.exclude-paths:}") private String excludePaths; ``` 或者使用`@Value`的`required`属性,但这可能不适用于所有情况。 7. **检查依赖管理**:确保项目中相关的Spring Boot配置处理器依赖存在,以便在编辑配置文件时能自动补全和验证属性。在Maven中添加: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> ``` 这有助于生成配置元数据,避免属性名错误。 8. **查看日志信息**:启动应用时,查看是否有关于未解析的属性的警告或错误信息,这可以帮助确定是否配置被正确加载。 此外,引用[4]中提到用户在处理JWT白名单时遇到拦截器配置的问题,可能需要检查拦截器配置是否正确加载了这些属性。例如,如果在过滤器或拦截器中直接使用`@Value`注入,可能需要确保该组件被Spring管理(如使用`@Component`),或者在配置类中通过`@Bean`方法创建实例时传入属性值,因为过滤器可能由Servlet容器管理,而不是Spring,导致注入失败。这种情况下,可以通过在配置类中获取属性值并手动设置到过滤器中。 例如,在配置类中: ```java @Configuration public class JwtConfig { @Value("${jwt.exclude-paths}") private String excludePaths; @Bean public JwtFilter jwtFilter() { return new JwtFilter(excludePaths); } } ``` 然后在JwtFilter的构造函数中接收该值。 总结,用户的问题可能源于属性未正确配置或注入方式不当,需要逐一排查配置文件和代码中的注入点。</think>在Spring Boot项目中解决自动注入失败并提示无法解析占位符`jwt.exclude-paths`的问题,需按以下步骤排查: ### 1. 检查配置文件 确保在`application.properties`或`application.yml`中正确定义了属性: ```yaml # application.yml示例 jwt: exclude-paths: /api/login,/api/refresh ``` 或 ```properties # application.properties示例 jwt.exclude-paths=/api/login,/api/refresh ``` ### 2. 验证属性注入方式 - **使用`@Value`直接注入**: ```java @Value("${jwt.exclude-paths}") private String excludePaths; // 单值 ``` 若属性为列表,改用数组或集合: ```java @Value("${jwt.exclude-paths}") private List<String> excludePaths; ``` - **通过配置类绑定**(推荐): ```java @Configuration @ConfigurationProperties(prefix = "jwt") public class JwtProperties { private List<String> excludePaths; // 必须提供getter和setter } ``` 在主启动类添加注解启用配置: ```java @SpringBootApplication @EnableConfigurationProperties(JwtProperties.class) public class Application { ... } ``` ### 3. 确保依赖配置处理器 在`pom.xml`中添加配置处理器依赖以支持属性自动提示和校验: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> ``` ### 4. 处理过滤器中的属性注入 若在过滤器中使用`@Value`,需确保过滤器实例由Spring管理。**避免直接`new`创建过滤器**,改用`@Bean`注入属性: ```java @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Value("${jwt.exclude-paths}") private List<String> excludePaths; @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(new JwtFilter(excludePaths), UsernamePasswordAuthenticationFilter.class); } } ``` ### 5. 检查配置文件加载 - 确认配置文件位于`src/main/resources`目录。 - 检查激活的Profile(如`application-dev.yml`)是否包含该属性。 ### 6. 验证属性名称和格式 - 确保属性名与代码中占位符**完全一致**(包括大小写)。 - YAML中使用缩进表示层级,避免格式错误。 ### 7. 查看启动日志 启动时关注以下日志信息: - `Binding properties source 'class path resource [application.yml]'`:确认配置文件已加载。 - `Not found vault/consul config`:排除外部配置覆盖问题。 - `Unrecognized field "jwt"`:表示属性前缀未正确绑定。 --- ### 常见问题示例 #### 错误:`Could not resolve placeholder 'jwt.exclude-paths'` - **原因**:属性未定义或拼写错误。 - **解决**:检查配置文件中的属性名和层级。 #### 错误:`Failed to bind properties under 'jwt'` - **原因**:配置类字段类型与属性值不匹配(如将列表定义为字符串)。 - **解决**:使用`List<String>`接收多值属性。 #### 过滤器无法注入属性 - **原因**:过滤器未通过Spring容器实例化。 - **解决**:通过`@Bean`方法创建过滤器并手动传入属性值[^4]。 --- ### 引用说明 [^1]: Kotlin Spring插件通过注解自动开放类和方法,需确保配置类被正确扫描。 : 拦截器配置需注意白名单顺序和实例化方式,避免属性无法注入。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值