首页 > 试题广场 >

找到搜索二叉树中两个错误的节点

[编程题]找到搜索二叉树中两个错误的节点
  • 热度指数:1500 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
一棵二叉树原本是搜索二叉树,但是其中有两个节点调换了位置,使得这棵二叉树不再是搜索二叉树,请按升序输出这两个错误节点的值。(每个节点的值各不相同)


输入描述:
第一行输入两个整数 n 和 root,n 表示二叉树的总节点个数,root 表示二叉树的根节点。

以下 n 行每行三个整数 fa,lch,rch,表示 fa 的左儿子为 lch,右儿子为 rch。(如果 lch 为 0 则表示 fa 没有左儿子,rch同理)

ps:节点的编号就是该节点的值。


输出描述:
请按升序输出这两个错误节点的值。
示例1

输入

3 1
1 2 3
2 0 0
3 0 0

输出

1 2

备注:

中序遍历找破坏序列单调递增性质的节点对
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Stack;
import java.util.LinkedList;
import java.util.Queue;

class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;
    public TreeNode(int val) {
        this.val = val;
    }
}

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        // 构建二叉树
        String[] params = br.readLine().split(" ");
        int n = Integer.parseInt(params[0]);
        TreeNode root = new TreeNode(Integer.parseInt(params[1]));
        HashMap<Integer, TreeNode> map = new HashMap<>();
        map.put(root.val, root);
        for(int i = 0; i < n; i++){
            params = br.readLine().split(" ");
            int val = Integer.parseInt(params[0]);
            int leftVal = Integer.parseInt(params[1]);
            int rightVal = Integer.parseInt(params[2]);
            TreeNode node = map.get(val);
            if(leftVal != 0) {
                node.left = new TreeNode(leftVal);
                map.put(leftVal, node.left);
            }
            if(rightVal != 0) {
                node.right = new TreeNode(rightVal);
                map.put(rightVal, node.right);
            }
        }
        System.out.println(isBST(root));
    }

    private static String isBST(TreeNode root) {
        int prev = Integer.MIN_VALUE;
        int error1 = 0, error2 = 0;
        Stack<TreeNode> stack = new Stack<>();
        while(!stack.isEmpty() || root != null){
            while(root != null){
                stack.push(root);
                root = root.left;
            }
            if(!stack.isEmpty()){
                root = stack.pop();
                if(root.val <= prev) {
                    // 破坏了中序遍历的单调递增特性
                    if(error1 == 0) error1 = prev;
                    error2 = root.val;
                }
                prev = root.val;
                root = root.right;
            }
        }
        if(error1 < error2)
            return error1 + " " + error2;
        else
            return error2 + " " + error1;
    }
}

发表于 2021-11-15 13:12:01 回复(0)
#include <bits/stdc++.h>
using namespace std;

struct Tree{
    int left, right;
};

vector<Tree> T;
vector<int> v1;

void BST(int r){
    if(r==0)
        return;
    BST(T[r].left);
    v1.push_back(r);
    BST(T[r].right);
}

int main(){
    int n, r, a, b, c;
    scanf("%d%d", &n, &r);
    T.resize(n+1);
    for(int i=0;i<n;i++){
        scanf("%d%d%d", &a, &b, &c);
        T[a].left = b;
        T[a].right = c;
    }
    BST(r);
    vector<int> v2(v1);
    sort(v2.begin(), v2.end());
    for(int i=0,k=0;i<v2.size();i++){
        if(v1[i]!=v2[i]){
            k++;
            if(k==1)
                printf("%d ", v2[i]);
            else{
                printf("%d\n", v2[i]);
                break;
            }
        }
    }
    return 0;
}

发表于 2020-06-15 11:25:40 回复(0)
//
// Created by yuanhao on 2019-9-2.
//
#include <iostream>
#include <cstring>

using namespace std;

/**
 * 对无序的几位进行排序 O(n)
 */
void sort(int *a, int n, int *wrong_index, int &wrong_index_len) {
    for (int i = 0; i < n - 1; ++i) {
        if (a[i] > a[i + 1]) {
            if (wrong_index[wrong_index_len - 1] != i) {
                wrong_index[wrong_index_len++] = i;
            }
            if (wrong_index[wrong_index_len - 1] != i + 1) {
                wrong_index[wrong_index_len++] = i + 1;
            }
            if (wrong_index_len >= 4) {
                // 两个数字交换,最多只有四个可能的位置不对
                break;
            }
        }
    }

    // 对最多四个位置的数字进行排序,随便选排序算法,冒泡就行
    for (int i = 0; i < wrong_index_len - 1; ++i) {
        for (int j = 0; j < wrong_index_len - 1 - i; j++) {
            if (a[wrong_index[j]] > a[wrong_index[j + 1]]) {
                int tmp = a[wrong_index[j]];
                a[wrong_index[j]] = a[wrong_index[j + 1]];
                a[wrong_index[j + 1]] = tmp;
            }
        }
    }
}


/**
 * 中序遍历 O(n)
 */
void mid_visite(int root, int *lch, int *rch, int *arr, int &num) {
    if (lch[root] != 0) {
        mid_visite(lch[root], lch, rch, arr, num);
    }
    arr[num++] = root;
    if (rch[root] != 0) {
        mid_visite(rch[root], lch, rch, arr, num);
    }
}

//题目描述
//一棵二叉树原本是搜索二叉树,但是其中有两个节点调换了位置,使得这棵二叉树不再是搜索二叉树,请按升序输出这两个错误节点的值。(每个节点的值各不相同)
//
//输入描述:
//第一行输入两个整数 n 和 root,n 表示二叉树的总节点个数,root 表示二叉树的根节点。
//
//以下 n 行每行三个整数 fa,lch,rch,表示 fa 的左儿子为 lch,右儿子为 rch。(如果 lch 为 0 则表示 fa 没有左儿子,rch同理)
//
//ps:节点的编号就是该节点的值。
//输出描述:
//请按升序输出这两个错误节点的值。
//示例1
//输入
//复制
//3 1
//1 2 3
//2 0 0
//3 0 0
//输出
//复制
//1 2
int main() {
    int n = 0;
    int root = 0;
    cin >> n >> root;
    int lch[n];
    int rch[n];
    for (int i = 0; i < n; ++i) {
        int f, l, r;
        cin >> f >> l >> r;
        lch[f] = l;
        rch[f] = r;
    }
    // 前面都是输入

    int num = 0;
    int arr[n];
    int sorted_arr[n];
    mid_visite(root, lch, rch, arr, num); // 实际上这个num最后是等于n的
    memcpy(sorted_arr, arr, num * sizeof(int));

    // 搜索树中序遍历的结果应该是一个有序的数组,这里有两位被交换,会导致最多四个位置的数字无序,排序之后就知道是哪两位交换了
    // 不用完整的排序,那样会超时,自己写一个排序算法
    int wrong_index[4];
    int wrong_index_len = 0;
    sort(sorted_arr, num, wrong_index, wrong_index_len);

    // 输出结果
    for (int i = 0; i < wrong_index_len; ++i) {
        if (arr[wrong_index[i]] != sorted_arr[wrong_index[i]]) {
            cout << sorted_arr[wrong_index[i]] << " ";
        }
    }
}

编辑于 2019-09-02 10:31:07 回复(0)
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner s =new Scanner(System.in);
        String[] a =s.nextLine().split(" ");
        int n=Integer.parseInt(a[0]);
        int rootvalue=Integer.parseInt(a[1]);
        HashMap<Integer,TreeNode> map=new HashMap<>();
        TreeNode root=new TreeNode(rootvalue);
        map.put(rootvalue,root);
        for(int i=0;i<n;i++){
            a =s.nextLine().split(" ");
            int val=Integer.parseInt(a[0]);
            int leftval=Integer.parseInt(a[1]);
            int rightval=Integer.parseInt(a[2]);
            TreeNode node=map.get(val);
            if(leftval!=0){
                node.left=new TreeNode(leftval);
                map.put(leftval,node.left);
            }
            if(rightval!=0){
                node.right=new TreeNode(rightval);
                map.put(rightval,node.right);
            }
        }
        int[] fing =new Main().fing(root);
         for(int i =0;i<fing.length;i++){
            System.out.print(fing[i]+" ");
        }
    }
    int[] result=new int[2];
    int index=1;
    TreeNode preNoed;
    public int[] fing(TreeNode root){
        if(root==null){
            return result;
        }
        fing(root.left);
        if(preNoed==null){
            preNoed=root;
        }
        if(index==1 && preNoed.val>root.val){
            result[1]=preNoed.val;
            index--;
        }
        if(index==0 && preNoed.val>root.val){
            result[0]=root.val;
        }
        preNoed=root;
        fing(root.right);
        return result;
    }
    
static class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;
    public TreeNode(int val) {
        this.val = val;
        }
    }
}
发表于 2022-11-17 17:32:32 回复(0)
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
struct node{
   int lchild;
   int rchild;
};
vector<node> v;
vector<int> v1,v2;
void inorder(int node){
    if(node==0)
        return;
    inorder(v[node].lchild);
    v1.push_back(node);
    v2.push_back(node);
    inorder(v[node].rchild);
}
int main(){
    int n,root;
    int n1,n2,n3;
    scanf("%d %d",&n,&root);
    v.resize(n+1);
    for(int i=0;i<n;++i){
        scanf("%d %d %d",&n1,&n2,&n3);
        v[n1].lchild=n2;
        v[n1].rchild=n3;
    }
    inorder(root);
    sort(v1.begin(),v1.end());
    int flag=0;
    for(int i=0;i<v1.size();++i){
        if(v1[i]!=v2[i])
            if(flag==0)
            {
                printf("%d",v1[i]);
                flag=1;
            }else{
                printf(" %d",v1[i]);
                break;
            }
    }
    return 0;
}

编辑于 2020-04-05 17:36:26 回复(0)
#include<bits/stdc++.h>
using namespace std;

// pre记录上一步访问的结点
// a,b即为所求
void Inorder(int root,int* lc,int* rc,int& pre,int& a,int& b,bool& first)
{
    if(!root) return;
    Inorder(lc[root],lc,rc,pre,a,b,first);
    // 因为是BST,中序遍历应为升序
    // 当出现降序时 说明找到了错误结点
    if(root<pre)
    {
        // 根据两个交换的结点的位置 可能出现一次或两次降序
        if(first)
        {
            a = pre;
            b = root;
            first = !first;
        }
        else b = root;
    }
    pre = root;
    Inorder(rc[root],lc,rc,pre,a,b,first);
}
int main()
{
    int n,root;
    cin>>n>>root;
    int p;
    int* lc = new int[n+1];
    int* rc = new int[n+1];
    for(int i=0;i<n;++i)
    {
        cin>>p;
        cin>>lc[p]>>rc[p];
    }
    int ans1,ans2;
    int pre = INT_MIN;
    bool first = true;
    Inorder(root,lc,rc,pre,ans1,ans2,first);
    ans1 = max(ans1,ans2);
    ans2 = min(ans1,ans2);
    cout<<ans2<<" "<<ans1<<endl;

    return 0;
}
发表于 2020-02-05 15:59:07 回复(0)