Find Bottom Left Tree Value

本文介绍了一种高效的方法来找到给定二叉树中最底层最左侧节点的值。通过深度优先搜索策略,确保了找到的节点是最底层且最左侧的节点。附带提供了完整的Java实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

Given a binary tree, find the leftmost value in the last row of the tree.

Example 1:

Input:

    2
   / \
  1   3

Output:
1

Example 2: 

Input:

        1
       / \
      2   3
     /   / \
    4   5   6
       /
      7

Output:
7

Note: You may assume the tree (i.e., the given root node) is not NULL.


tips:这题我只是知道如何遍历所有节点,但是对于树深度的把握不是很好,上网搜索找到了一个十分巧妙地方法。记录一下,下次面对类似题目不会束手无措

源码如下:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
   private int result = 0, height = 0;
   public int findBottomLeftValue(TreeNode root) {
         helper(root, 1);
         return result;
     }
     
     private void helper(TreeNode root, int depth) {
         if (root == null) return;
         
         if (height < depth) {
             result = root.val;  //这里很巧妙,只有第一次递归到才会由于深度变化而改变,换句话说,保证是左子树来修改
             height = depth;
         }
         
         helper(root.left, depth + 1);
         helper(root.right, depth + 1);
         }
}



组件代码: <template> <div class="left-tree-wrap"> <el-input v-if="props.showSearch" class="left-tree-input" v-model="searchData" :placeholder="props.searchPlaceholder" :prefix-icon="Search" clearable @input="debouncedInput" /> <el-button v-if="props.showAddBtn" class="left-tree-btn" type="primary" :icon="Plus" @click="handleClick"> {{ props.addBtnText }} </el-button> <div class="tree-scroll"> <el-tree ref="treeRef" :data="filteredTreeData" :props="props.treeProps" :check-strictly="props.checkStrictly" :nodeKey="props.treeProps.nodeKey" :show-checkbox="props.showCheckbox" @check="handleCheck" @node-click="handleNodeClick" highlight-current :default-checked-keys="props.selectedNodes" :current-node-key="currentNodeKey" :default-expanded-keys="expandedList" @node-expand="handleNodeExpand" @node-collapse="handleNodeCollapse" > <template #default="{ node, data }"> <div class="tree-wrap"> <span class="text" :style="`width: ${labelWidth}px`"> {{ node.label }} <slot name="label" :node="data"></slot> </span> <el-dropdown v-if="props.operateList && props.operateList.length > 0" @command="e => handleCommand(node, e)"> <span class="icon"> <el-icon v-if="data.noShowIcon !== true"> <More /> </el-icon> </span> <template #dropdown> <el-dropdown-menu> <el-dropdown-item v-for="(item, index) in props.operateList" :key="index" :command="item.type"> {{ item.name }} </el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> </div> </template> </el-tree> </div> </div> </template> <script setup> import { ref, onMounted, watch, computed, getCurrentInstance } from 'vue'; import { Search, Plus } from '@element-plus/icons-vue'; import { useRouter } from 'vue-router'; import { debounce } from 'lodash'; import i18n from '@/locale/index'; defineOptions({ name: 'jl-left-tree' }); const { appContext } = getCurrentInstance(); const { $utils, $request, $message, $rules } = appContext.config.globalProperties; const emit = defineEmits(['checkCb', 'addCb', 'searchCb', 'treeOperateCb', 'clickTree']); const props = defineProps({ type: { type: String, default: 'primary' }, operateList: { type: Array, default: () => [] }, showSearch: { type: Boolean, default: false }, searchPlaceholder: { type: String, default: i18n.global.t('请输入') }, addBtnText: { type: String, default: i18n.global.t('新增') }, showAddBtn: { type: Boolean, default: false }, treeProps: { type: Object, default: () => { let obj = { label: 'label', children: 'children', nodeKey: 'id' }; return obj; } }, treeData: { type: Array, default: () => [] }, showCheckbox: { type: Boolean, default: false }, selectTreeData: { type: Object, default: () => {} }, // 默认展开 defaultExpanded: { type: Array, default: () => [] }, // 树label宽度 labelWidth: { type: [String, Number], default: 120 }, selectedNodes: { type: Array, default: () => [] }, checkStrictly: { type: Boolean, default: false }, isFilter: { type: Boolean, default: false } }); let currentNodeKey = ref(); // 选中节点 let treeRef = ref(); let searchData = ref(''); let originalTreeData = ref([]); // 保存原始树数据 // 创建深拷贝函数 const deepClone = (data) => { return JSON.parse(JSON.stringify(data)); }; let expandedList = ref([]); // 过滤树数据 const filteredTreeData = computed(() => { if (!props.isFilter || !searchData.value) { return originalTreeData.value; } const filter = searchData.value.toLowerCase(); const propsLabel = props.treeProps.label; const filterData = (data) => { return data.filter(item => { const label = item[propsLabel]?.toString().toLowerCase() || ''; // 检查当前节点是否匹配 const isMatch = label.includes(filter); // 递归过滤子节点 if (item.children && item.children.length > 0) { const filteredChildren = filterData(item.children); if (filteredChildren.length > 0) { // 如果有匹配的子节点,保留当前节点及其子节点 return { ...item, children: filteredChildren }; } } // 如果没有子节点或子节点不匹配,但当前节点匹配,则保留 return isMatch ? item : null; }).filter(Boolean); // 过滤掉null值 }; return filterData(deepClone(originalTreeData.value)); }); // 监听原始树数据变化 watch( () => props.treeData, (newValue) => { originalTreeData.value = deepClone(newValue); }, { immediate: true, deep: true } ); watch( () => props.selectTreeData, (newValue) => { if (newValue) { currentNodeKey.value = newValue[props.treeProps.nodeKey]; } }, { immediate: true, deep: true } ); /** * 树选中 */ const handleCheck = (data, e) => { emit('checkCb', { data, e }); }; /** * 新增按钮 */ const handleClick = () => { emit('addCb'); }; /** * 搜索 */ const handleInputChange = (e) => { if (props.isFilter) { // 前端过滤,无需额外处理 } else { emit('searchCb', e); } }; // 创建防抖函数 const debouncedInput = debounce(handleInputChange, 500); /** * 树更多菜单 */ const handleCommand = (item, type) => { emit('treeOperateCb', { item: item.data, type }); }; /** * 点击树节点 */ const handleNodeClick = (data, treeNode, treeNode1, treeNode2) => { emit('clickTree', data); }; /** * 展开树节点 */ const handleNodeExpand = (data, node, e) => { expandedList.value.push(data[props.treeProps.nodeKey]); }; /** * 收起树节点 */ const handleNodeCollapse = (data, node, e) => { let index = expandedList.value.findIndex(item => item === data[props.treeProps.nodeKey]); expandedList.value.splice(index, 1); }; onMounted(() => { expandedList.value = props.defaultExpanded; }); </script> <style scoped lang="scss"> .left-tree-wrap { padding: 12px; display: flex; flex-flow: column nowrap; height: 100%; .left-tree-input { margin-bottom: 12px; } .left-tree-btn { width: 100%; margin-bottom: 12px; } .tree-scroll { :deep(.el-tree-node__content) { padding-top: 20px !important; padding-bottom: 20px !important; padding-right: 8px; } overflow-y: auto; flex-shrink: 2; .tree-wrap { display: flex; justify-content: space-between; align-items: center; width: 100%; .text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; width: 120px; } } .icon { border-radius: 4px; display: flex; justify-content: center; align-items: center; width: 20px; height: 20px; &:hover { background: #c8c9cc; } } } } </style> 页面使用: <jl-left-tree1 :treeData="treeData" showSearch :labelWidth="230" showCheckbox :isFilter="true" @checkCb="checkCb" :searchPlaceholder="t('请输入名称')" :treeProps="{ label: 'itemName', children: 'deviceList', nodeKey: 'id' }" @clickTree="clickTree" @searchCb="searchCb" :selectTreeData="selectTreeData" :selectedNodes="selectedNodes" ></jl-left-tree1> // 数选择 const checkCb = item => { console.log('item', item) selectedNodes.value = item.e.checkedKeys; isChange.value = true; }; /** * 树点击 */ const clickTree = data => { selectTreeData.value = data; }; // 树搜索 const searchCb = e => { devPointScreen(e, true); }; let selectTreeData = ref({}); // 选中树的数据 let selectedNodes = ref([]); // 被选中的节点数组 帮我综合分析并解决问题:当我在输入框输入文字利用isFilter=true进行过滤后,将搜索出来的节点进行勾选时会将搜索前已经勾选的节点取消勾选,同理,当我操作搜索结果节点取消勾选时也会将搜索前已勾选的取消勾选,解决此问题,输出为完整组件代码以及页面代码,保证我要的效果(当我搜索后勾选时就只操作当前操作的节点--对应搜索前的所有节点中,当我取消勾选时也只操作取消勾选的节点)
最新发布
06-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值