03 大厂高频算法和数据结构面试题3

345 阅读6分钟

本节所有题目、思路、代码参考了左程云老师“算法与数据结构大厂刷题班”的部分内容,特此说明。

题目1:LongestSubstringWithoutRepeatingCharacters

问题描述

求一个字符串中,最长无重复字符子串长度

思路

【字符串dp】

  • 字符串问题,考虑以i位置结尾的字符串往前推,推到一个最长无重复的串的最长长度
  • 也就是推到不能再推
  • i位置的答案有两个因素决定
  • 一个是i位置的字符上次出现的位置
  • 一个是i-1位置的字符最远能推到哪
  • 第一个因素用hash表(数组就可以)记录
  • 第二个直接取出i-1位置的答案
  • 由于i位置的答案只需要用到i-1位置的答案
  • 所以没必要记录所有的答案,直接用一个pre变量滚动接收每次的答案当作下一位的i-1位置的答案即可

代码

package class03;

// 本题测试链接 : https://leetcode.com/problems/longest-substring-without-repeating-characters/
// 最长不重复字串
// 字串:开头结尾
public class Code01_LongestSubstringWithoutRepeatingCharacters {

    //决定因素1,上次出现的位置
    //决定因素2,前一个推不到的地方,这个位置也推不到
    //谁离得近,取谁作为能推出来的长度

    //当前字符上次出现的位置怎么维护? 很简单,直接用一张hashmap
    public static int lengthOfLongestSubstring(String s) {
        if (s == null || s.equals("")) {
            return 0;
        }
        char[] str = s.toCharArray();
        int[] map = new int[256];
        for (int i = 0; i < 256; i++) {
            map[i] = -1;
        }
        map[str[0]] = 0;
        int N = str.length;
        int ans = 1;
        int pre = 1;
        for (int i = 1; i < N; i++) {
            pre = Math.min(i - map[str[i]], pre + 1);
            ans = Math.max(ans, pre);
            map[str[i]] = i;
        }
        return ans;
    }

    public static void main(String[] args) {
        System.out.println(lengthOfLongestSubstring("xialinxiarbw"));
    }

}

题目2:HowManyTypes

问题描述

只由小写字母(a~z)组成的一批字符串,都放在字符类型的数组String[] arr中,如果其中某两个字符串所含有的字符种类完全一样 就将两个字符串算作一类,比如baacbba和bac就算作一类,返回arr中有多少类

思路

【位图】

  • 一个整数表示一个摘要
  • 一个整数26位,用位图实现
  • 如果字符串出现A,这个整数的第0位标1
  • 如果出现字符串B,这个整数的第1位标1
  • 一个字符串处理完,必定会生成一个整数,存进去hashset
  • 怎么标?准备一个32位都为0的整数,某一位标1的方法是,把1左移到这一位,或进去

代码

package class03;

import java.util.HashSet;

public class Code02_HowManyTypes {

    /*
* 只由小写字母(a~z)组成的一批字符串,都放在字符类型的数组String[] arr中,
* 如果其中某两个字符串,所含有的字符种类完全一样,就将两个字符串算作一类 比如:baacba和bac就算作一类
* 虽然长度不一样,但是所含字符的种类完全一样(a、b、c) 返回arr中有多少类?
*/

    public static int types1(String[] arr) {
        HashSet<String> types = new HashSet<>();
        for (String str : arr) {
            char[] chs = str.toCharArray();
            boolean[] map = new boolean[26];
            for (int i = 0; i < chs.length; i++) {
                map[chs[i] - 'a'] = true;
            }
            String key = "";
            for (int i = 0; i < 26; i++) {
                if (map[i]) {
                    key += String.valueOf((char) (i + 'a'));
                }
            }
            types.add(key);
        }
        return types.size();
    }

    public static int types2(String[] arr) {
        HashSet<Integer> types = new HashSet<>();
        for (String str : arr) {
            char[] chs = str.toCharArray();
            int key = 0;
            for (int i = 0; i < chs.length; i++) {
                key |= (1 << (chs[i] - 'a'));
            }
            types.add(key);
        }
        return types.size();
    }

    // for test
    public static String[] getRandomStringArray(int possibilities, int strMaxSize, int arrMaxSize) {
        String[] ans = new String[(int) (Math.random() * arrMaxSize) + 1];
        for (int i = 0; i < ans.length; i++) {
            ans[i] = getRandomString(possibilities, strMaxSize);
        }
        return ans;
    }

    // for test
    public static String getRandomString(int possibilities, int strMaxSize) {
        char[] ans = new char[(int) (Math.random() * strMaxSize) + 1];
        for (int i = 0; i < ans.length; i++) {
            ans[i] = (char) ((int) (Math.random() * possibilities) + 'a');
        }
        return String.valueOf(ans);
    }

    public static void main(String[] args) {
        int possibilities = 5;
        int strMaxSize = 10;
        int arrMaxSize = 100;
        int testTimes = 500000;
        System.out.println("test begin, test time : " + testTimes);
        for (int i = 0; i < testTimes; i++) {
            String[] arr = getRandomStringArray(possibilities, strMaxSize, arrMaxSize);
            int ans1 = types1(arr);
            int ans2 = types2(arr);
            if (ans1 != ans2) {
                System.out.println("Oops!");
            }
        }
        System.out.println("test finish");

    }

}

题目3:Largest1BorderedSquare

问题描述

给定一个只有0和1组成的二维数组,返回边框全是1(内部无所谓)的最大正方形面积

思路

【预处理数组方法】

  • 几个心里有数的结论:
  • NN区域中,长方形数量级是N4(N2N2,选两个点的可能性)
  • NN区域中,正方形的数量级是N3(N2N,选一个点和边长的可能性)
  • 法1,枚举所有正方形,往右下方向,两个for枚举点的可能性,边长枚举时候,右、下哪个距离短选哪个当作边长最大值,可以枚举所有正方形。如何验证正方形边框是不是1,最好O(1)?
  • 维护一个表,(i,j)位置右边有多少个连续的1,下边有多少个连续的1。判断的时候调三个点的信息即可。
  • 表怎么生成?两个二维数组,一个生成每个点右边连续的1;一个生成每个点下边连续的1;遍历一边生成右信息,从右到左遍历,如果原数组这个位置是1,++就可,如果是0,归零。下信息同理。

代码

package class03;

// 本题测试链接 : https://leetcode.com/problems/largest-1-bordered-square/
public class Code03_Largest1BorderedSquare {

    public static int largest1BorderedSquare(int[][] m) {
        int[][] right = new int[m.length][m[0].length];
        int[][] down = new int[m.length][m[0].length];
        setBorderMap(m, right, down);
        for (int size = Math.min(m.length, m[0].length); size != 0; size--) {
            if (hasSizeOfBorder(size, right, down)) {
                return size * size;
            }
        }
        return 0;
    }

    public static void setBorderMap(int[][] m, int[][] right, int[][] down) {
        int r = m.length;
        int c = m[0].length;
        if (m[r - 1][c - 1] == 1) {
            right[r - 1][c - 1] = 1;
            down[r - 1][c - 1] = 1;
        }
        for (int i = r - 2; i != -1; i--) {
            if (m[i][c - 1] == 1) {
                right[i][c - 1] = 1;
                down[i][c - 1] = down[i + 1][c - 1] + 1;
            }
        }
        for (int i = c - 2; i != -1; i--) {
            if (m[r - 1][i] == 1) {
                right[r - 1][i] = right[r - 1][i + 1] + 1;
                down[r - 1][i] = 1;
            }
        }
        for (int i = r - 2; i != -1; i--) {
            for (int j = c - 2; j != -1; j--) {
                if (m[i][j] == 1) {
                    right[i][j] = right[i][j + 1] + 1;
                    down[i][j] = down[i + 1][j] + 1;
                }
            }
        }
    }

    public static boolean hasSizeOfBorder(int size, int[][] right, int[][] down) {
        for (int i = 0; i != right.length - size + 1; i++) {
            for (int j = 0; j != right[0].length - size + 1; j++) {
                if (right[i][j] >= size && down[i][j] >= size && right[i + size - 1][j] >= size
                    && down[i][j + size - 1] >= size) {
                    return true;
                }
            }
        }
        return false;
    }

}

题目4:MaxPairNumber

问题描述

给定一个数组arr,代表每个人的能力值。再给定一个非负数k,如果两个人能力差值正好为k,那么可以凑在一起比赛 一局比赛只有两个人,返回最多可以同时有多少场比赛

思路

代码

package class03;

import java.util.Arrays;

// 给定一个数组arr,代表每个人的能力值。再给定一个非负数k。
// 如果两个人能力差值正好为k,那么可以凑在一起比赛,一局比赛只有两个人
// 返回最多可以同时有多少场比赛
public class Code04_MaxPairNumber {

    // 暴力解
    public static int maxPairNum1(int[] arr, int k) {
        if (k < 0) {
            return -1;
        }
        return process1(arr, 0, k);
    }

    public static int process1(int[] arr, int index, int k) {
        int ans = 0;
        if (index == arr.length) {
            for (int i = 1; i < arr.length; i += 2) {
                if (arr[i] - arr[i - 1] == k) {
                    ans++;
                }
            }
        } else {
            for (int r = index; r < arr.length; r++) {
                swap(arr, index, r);
                ans = Math.max(ans, process1(arr, index + 1, k));
                swap(arr, index, r);
            }
        }
        return ans;
    }

    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    // 时间复杂度O(N*logN)
    //排序+窗口
    // 差值广义上递增,用左右两个指针代表当时选的两个人
    //贪心的点在于,让小值的人先凑比赛,最终一定不会有情况比这种策略下更多
    //看L位置的人能不能被满足
    //R不会重复,因为R一直往右跑
    public static int maxPairNum2(int[] arr, int k) {
        if (k < 0 || arr == null || arr.length < 2) {
            return 0;
        }
        Arrays.sort(arr);
        int ans = 0;
        int N = arr.length;
        int L = 0;
        int R = 0;
        //用过没有
        boolean[] usedR = new boolean[N];
        //正式的寻找过程
        while (L < N && R < N) {
            //L使用过,右移
            if (usedR[L]) {
                L++;
            } else if (L >= R) {//没有或者一个人
                R++;
            } else { // 不止一个数,而且都没用过!
                //差值是多少
                int distance = arr[R] - arr[L];
                if (distance == k) {//如果刚好是K
                    ans++;
                    usedR[R++] = true;
                    L++;
                } else if (distance < k) {//距离小,L++
                    R++;
                } else {//距离大
                    L++;
                }
            }
        }
        return ans;
    }

    // 为了测试
    public static int[] randomArray(int len, int value) {
        int[] arr = new int[len];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * value);
        }
        return arr;
    }

    // 为了测试
    public static void printArray(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }

    // 为了测试
    public static int[] copyArray(int[] arr) {
        int[] ans = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            ans[i] = arr[i];
        }
        return ans;
    }

    public static void main(String[] args) {
        int maxLen = 10;
        int maxValue = 20;
        int maxK = 5;
        int testTime = 1000;
        System.out.println("功能测试开始");
        for (int i = 0; i < testTime; i++) {
            int N = (int) (Math.random() * (maxLen + 1));
            int[] arr = randomArray(N, maxValue);
            int[] arr1 = copyArray(arr);
            int[] arr2 = copyArray(arr);
            int k = (int) (Math.random() * (maxK + 1));
            int ans1 = maxPairNum1(arr1, k);
            int ans2 = maxPairNum2(arr2, k);
            if (ans1 != ans2) {
                System.out.println("Oops!");
                printArray(arr);
                System.out.println(k);
                System.out.println(ans1);
                System.out.println(ans2);
                break;
            }
        }
        System.out.println("功能测试结束");
    }

}

题目5:Code05_BoatsToSavePeople

问题描述

给定一个正数数组arr,代表若干人的体重,再给定一个正数limit,表示所有船共同拥有的载重量,每艘船最多坐两人,且不能超过载重 想让所有的人同时过河,并且用最好的分配方法让船尽量少,返回最少的船数 Leetcode链接 : leetcode.com/problems/bo…

思路

  • 边界判断,有人体重比limit大,返回无穷大
  • 排序
  • 卡<=(limit / 2)最右的位置,L指向它,R指向后一个
  • 整体贪心思想:极大极小相互吞噬
  • 构建例子去想边界吧,有点麻烦
  • 中间分界点开始往左右两边划

代码

package class03;

import java.util.Arrays;

// 给定一个正数数组arr,代表若干人的体重
// 再给定一个正数limit,表示所有船共同拥有的载重量
// 每艘船最多坐两人,且不能超过载重
// 想让所有的人同时过河,并且用最好的分配方法让船尽量少
// 返回最少的船数
// 测试链接 : https://leetcode.com/problems/boats-to-save-people/
public class Code05_BoatsToSavePeople {

    public static int numRescueBoats1(int[] arr, int limit) {
        if (arr == null || arr.length == 0) {
            return 0;
        }
        int N = arr.length;
        Arrays.sort(arr);
        if (arr[N - 1] > limit) {
            return -1;
        }
        int lessR = -1;
        for (int i = N - 1; i >= 0; i--) {
            if (arr[i] <= (limit / 2)) {
                lessR = i;
                break;
            }
        }
        if (lessR == -1) {
            return N;
        }
        int L = lessR;
        int R = lessR + 1;
        int noUsed = 0;
        while (L >= 0) {
            int solved = 0;
            while (R < N && arr[L] + arr[R] <= limit) {
                R++;
                solved++;
            }
            if (solved == 0) {
                noUsed++;
                L--;
            } else {
                L = Math.max(-1, L - solved);
            }
        }
        int all = lessR + 1;
        int used = all - noUsed;
        int moreUnsolved = (N - all) - used;
        return used + ((noUsed + 1) >> 1) + moreUnsolved;
    }

    // 首尾双指针的解法
    public static int numRescueBoats2(int[] people, int limit) {
        Arrays.sort(people);
        int ans = 0;
        int l = 0;
        int r = people.length - 1;
        int sum = 0;
        while (l <= r) {
            sum = l == r ? people[l] : people[l] + people[r];
            if (sum > limit) {
                r--;
            } else {
                l++;
                r--;
            }
            ans++;
        }
        return ans;
    }

}

题目6:ClosestSubsequenceSum

问题描述

给定整数数组nums和目标值goal,需要从nums中选出一个子序列,使子序列元素总和最接近goal 也就是说如果子序列元素和为sum ,需要最小化绝对差abs(sum - goal),返回 abs(sum - goal)可能的最小值 注意数组的子序列是通过移除原始数组中的某些元素(可能全部或无)而形成的数组。 数据范围: 0<=nums.length<=40 0<=nums[i]<=108 0<=goal<=108

思路

【分治】

  • 数组长度少,用分治
  • 具体做法是
    • 把40拆成左右两半:
    • 左边暴力枚举出所有的累加和的情况,每一个位置可以选和不选,一共是220的复杂度
    • 同理,右边暴力枚举出所有的累加和也是220复杂度
    • 目标是让累加和与给定了target最接近
  • 那么有这么几种情况,左边的某一个累加和有一个根target最接近的
  • 右边也有一个累加和与target最接近的
  • 或者,左边给我一个累加和,右边选哪一个累加和加起来更近,这个交叉计算的时间复杂度是多少呢?
  • 其实左边任选一个累加和x是220,选定这个的情况下,问题就变成了
  • 在右侧找出距离target - x最近的数。最好的做法是右边用有序表存,查询距离某个值最近的数 直接二分得log2220=20
  • 因此交叉计算的时间复杂度能做到20*220
  • 总的时间复杂度就是220+220+20220=11221能过

代码

package class03;

import java.util.Arrays;

// 本题测试链接 : https://leetcode.com/problems/closest-subsequence-sum/
// 本题数据量描述:
// 1 <= nums.length <= 40
// -10^7 <= nums[i] <= 10^7
// -10^9 <= goal <= 10^9
// 通过这个数据量描述可知,需要用到分治,因为数组长度不大
// 而值很大,用动态规划的话,表会爆
public class Code06_ClosestSubsequenceSum {

    public static int[] l = new int[1 << 20];
    public static int[] r = new int[1 << 20];

    public static int minAbsDifference(int[] nums, int goal) {
        if (nums == null || nums.length == 0) {
            return goal;
        }
        int le = process(nums, 0, nums.length >> 1, 0, 0, l);
        int re = process(nums, nums.length >> 1, nums.length, 0, 0, r);
        Arrays.sort(l, 0, le);
        Arrays.sort(r, 0, re--);
        int ans = Math.abs(goal);
        for (int i = 0; i < le; i++) {
            int rest = goal - l[i];
            while (re > 0 && Math.abs(rest - r[re - 1]) <= Math.abs(rest - r[re])) {
                re--;
            }
            ans = Math.min(ans, Math.abs(rest - r[re]));
        }
        return ans;
    }

    public static int process(int[] nums, int index, int end, int sum, int fill, int[] arr) {
        if (index == end) {
            arr[fill++] = sum;
        } else {
            fill = process(nums, index + 1, end, sum, fill, arr);
            fill = process(nums, index + 1, end, sum + nums[index], fill, arr);
        }
        return fill;
    }

}

题目7:FreedomTrail

题目描述

电子游戏“辐射4”中,任务“通向自由”要求玩家到达名为“Freedom Trail Ring”的金属表盘,并使用表盘拼写特定关键词才能开门 给定一个字符串 ring,表示刻在外环上的编码;给定另一个字符串 key,表示需要拼写的关键词。您需要算出能够拼写关键词中所有字符的最少步数 最初,ring 的第一个字符与12:00方向对齐。您需要顺时针或逆时针旋转 ring 以使 key 的一个字符在 12:00 方向对齐,然后按下中心按钮,以此逐个拼写完 key 中的所有字符 旋转 ring 拼出 key 字符 key[i] 的阶段中: 您可以将 ring 顺时针或逆时针旋转一个位置,计为1步。旋转的最终目的是将字符串 ring 的一个字符与 12:00 方向对齐,并且这个字符必须等于字符 key[i] 。 如果字符 key[i] 已经对齐到12:00方向,您需要按下中心按钮进行拼写,这也将算作 1 步。按完之后,您可以开始拼写 key 的下一个字符(下一阶段), 直至完成所有拼写。 Leetcode题目:leetcode.com/problems/fr…

思路

  • 先处理几个小函数:
    • 第一个是从i位置拨到j位置最省的代价,返回;这个很简答,正和逆就能搞定,取最小值
    • 第二是处理之前预处理出一张表,比如字符串“afaxacf”,哪些位置都是a,哪些位置都是f……
  • 然后dfs,看拨到当前字符有多少种选择,递归就行,水
  • 参数:
    • preButton:指针指向的上一个按键是几
    • keyIndex:此时要转到谁(搞定哪个字符)
    • map:任何一种字符在电话里哪些位置有(HashMap<Character,ArrayList>)
    • N:电话机有多少个字符
    • str:要搞定的串
  • 这个dfs直接改记忆化搜索,应该就是最优解
  • dfs过程:
    • 终止位置:return 0
    • 当前要搞定的字符拿出来,哪些位置可选拿出来
    • 初始话这一步的全局最大值
    • 选每一个位置,更新代价是拨号代价+确认代价+后续搞定
    • 然后改成记忆化搜索直接提速
  • 总结一下这个题,最重要的是在写之前想好具体过程,写一个大致例子串一串;想想要卡的边界,不然dfs很容易错

代码

package class03;
o
import java.util.ArrayList;
import java.util.HashMap;

// 本题测试链接 : https://leetcode.com/problems/freedom-trail/
public class Code07_FreedomTrail {

    public static int findRotateSteps(String r, String k) {
        char[] ring = r.toCharArray();
        int N = ring.length;
        HashMap<Character, ArrayList<Integer>> map = new HashMap<>();
        for (int i = 0; i < N; i++) {
            if (!map.containsKey(ring[i])) {
                map.put(ring[i], new ArrayList<>());
            }
            map.get(ring[i]).add(i);
        }
        char[] str = k.toCharArray();
        int M = str.length;
        int[][] dp = new int[N][M + 1];
        // hashmap
        // dp[][] == -1 : 表示没算过!
        for (int i = 0; i < N; i++) {
            for (int j = 0; j <= M; j++) {
                dp[i][j] = -1;
            }
        }
        return process(0, 0, str, map, N, dp);
    }

    // 电话里:指针指着的上一个按键preButton
    // 目标里:此时要搞定哪个字符?keyIndex
    // map : key 一种字符 value: 哪些位置拥有这个字符
    // N: 电话大小
    // f(0, 0, aim, map, N)
    public static int process(int preButton, int index, char[] str, HashMap<Character, ArrayList<Integer>> map, int N,
                              int[][] dp) {
        if (dp[preButton][index] != -1) {
            return dp[preButton][index];
        }
        int ans = Integer.MAX_VALUE;
        if (index == str.length) {
            ans = 0;
        } else {
            // 还有字符需要搞定呢!
            char cur = str[index];
            ArrayList<Integer> nextPositions = map.get(cur);
            for (int next : nextPositions) {
                int cost = dial(preButton, next, N) + 1 + process(next, index + 1, str, map, N, dp);
                ans = Math.min(ans, cost);
            }
        }
        dp[preButton][index] = ans;
        return ans;
    }

    public static int dial(int i1, int i2, int size) {
        return Math.min(Math.abs(i1 - i2), Math.min(i1, i2) + size - Math.max(i1, i2));
    }

}

题目8

题目描述

给定三个参数,二叉树的头节点head,树上某个节点target,正数K。从target开始,可以向上走或者向下走,返回与target的距离是K的所有节点

思路

二叉树的递归】【图的bfs】【树的图处理化】

  • 本质就是一个节点往三个方向走
  • 核心就是怎么获取三个方向的节点
  • 很简单,左右子节点通过左右指针获取即可
  • 怎么获取父节点呢?
  • 很好办,在bfs之前先去生成一张hash表,记录一下每个节点的父节点,递归就行
  • 这样通过查表就能知道第三个方向的节点了!
  • 下面是距离问题,
  • 具体其实就是层数问题
  • 怎么在bfs中抓层数呢?
  • 很简单,一次处理一层的节点,这样留在queue中的必定是一层的!
  • 只需要用一个变量记录一下当前是第几层就行了;
  • 发现满足K了把满足的节点记在list里边返回就行了!

代码

package class03;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class Code08_DistanceKNodes {

    public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node(int v) {
            value = v;
        }
    }

    //bfs队列中标记层数的方法:队列中元素的个数(因为知道个数)
    public static List<Node> distanceKNodes(Node root, Node target, int K) {
        HashMap<Node, Node> parents = new HashMap<>();
        parents.put(root, null);
        //获得父亲节点列表
        createParentMap(root, parents);

        Queue<Node> queue = new LinkedList<>();
        //有没有进入过队列
        HashSet<Node> visited = new HashSet<>();


        //进过队列就登记
        queue.offer(target);
        visited.add(target);

        //当前层数,到达第K层的时候收集节点就可以
        int curLevel = 0;

        //收集到这里
        List<Node> ans = new ArrayList<>();


        while (!queue.isEmpty()) {
            //这一批有多少个节点,一定是上一次的某个的周围
            //一批就是同一层
            int size = queue.size();
            //处理一批节点(同一层)
            while (size-- > 0) {
                Node cur = queue.poll();

                //如果是第K层,加入到答案数组里边去
                if (curLevel == K) {
                    ans.add(cur);
                }


                //三种情况放队列
                if (cur.left != null && !visited.contains(cur.left)) {
                    visited.add(cur.left);
                    queue.offer(cur.left);
                }
                if (cur.right != null && !visited.contains(cur.right)) {
                    visited.add(cur.right);
                    queue.offer(cur.right);
                }
                if (parents.get(cur) != null && !visited.contains(parents.get(cur))) {
                    visited.add(parents.get(cur));
                    queue.offer(parents.get(cur));
                }


            }
            curLevel++;
            //收集完答案
            if (curLevel > K) {
                break;
            }
        }
        return ans;
    }

    //建一张父亲表,用于找到父亲
    public static void createParentMap(Node cur, HashMap<Node, Node> parents) {
        if (cur == null) {
            return;
        }
        if (cur.left != null) {
            parents.put(cur.left, cur);
            createParentMap(cur.left, parents);
        }
        if (cur.right != null) {
            parents.put(cur.right, cur);
            createParentMap(cur.right, parents);
        }
    }

    public static void main(String[] args) {
        Node n0 = new Node(0);
        Node n1 = new Node(1);
        Node n2 = new Node(2);
        Node n3 = new Node(3);
        Node n4 = new Node(4);
        Node n5 = new Node(5);
        Node n6 = new Node(6);
        Node n7 = new Node(7);
        Node n8 = new Node(8);

        n3.left = n5;
        n3.right = n1;
        n5.left = n6;
        n5.right = n2;
        n1.left = n0;
        n1.right = n8;
        n2.left = n7;
        n2.right = n4;

        Node root = n3;
        Node target = n5;
        int K = 2;

        List<Node> ans = distanceKNodes(root, target, K);
        for (Node o1 : ans) {
        	System.out.println(o1.value);
        }
	}

}

如有问题,欢迎各位大佬指正

� �