跳转至

Leetcode刷题笔记

int **graph,int graphsize表示graph二维数组有多少行

int* graphcolsize表示每行有多少列

C
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
bool isValidBST(struct TreeNode* root) {
    if(root==NULL)return true;
    if(root->left&&root->left->val>=root->val)return false;
    if(root->right&&root->right->val<=root->val)return false;
    if(isValidBST(root->left)&&isValidBST(root->right))return true;
    else{
        return false;
    }
}

验证二叉搜索树:用中序遍历

C
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

bool isBSTUtil(struct TreeNode* root, long min, long max) {
    if (root == NULL) {
        return true;
    }

    if (root->val <= min || root->val >= max) {
        return false;
    }

    return isBSTUtil(root->left, min, root->val) && isBSTUtil(root->right, root->val, max);
}

bool isValidBST(struct TreeNode* root) {
    return isBSTUtil(root, LONG_MIN, LONG_MAX);
}
C
int count=0;
int a[20000];
bool isValidBST(struct TreeNode* root) {
    in_order(root);
    if(count==1)return true;
    for(int i=0;i<count-1;i++){
        if(a[i]>a[i+1])return false;
    }
    return true;
}

void in_order(struct TreeNode* root){
    if(root==NULL)return;
    in_order(root->left);
    a[count++]=root->val;
    in_order(root->right);
}

230

C
int count;
int kthSmallestUtil(struct TreeNode* root, int k) {
    if (root == NULL) {
        return -1; 
    }
    int leftResult = kthSmallestUtil(root->left, k);
    if (leftResult != -1) {
        return leftResult;
    }
    count++;
    if (count == k) {
        return root->val; // Found the kth smallest element
    }

    return kthSmallestUtil(root->right, k);
}

int kthSmallest(struct TreeNode* root, int k) {
    count = 0;
    return kthSmallestUtil(root, k);
}

797. 所有可能的路径

给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序

graph[i] 是一个从节点 i 可以访问的所有节点的列表(即从节点 i 到节点 graph[i][j]存在一条有向边)。

分治思想:

回溯注重边的选择,撤销在for循环内

和DFS一样,先看是否走通了一条路径/走到头了一条路径

如果没有,就将当前位置相邻的下一层所有的可能性都遍历一遍

二叉树的重要性

举个例子,比如两个经典排序算法 快速排序归并排序,对于它俩,你有什么理解?

如果你告诉我,快速排序就是个二叉树的前序遍历,归并排序就是个二叉树的后序遍历,那么我就知道你是个算法高手了

为什么快速排序和归并排序能和二叉树扯上关系?我们来简单分析一下他们的算法思想和代码框架:

快速排序的逻辑是,若要对 nums[lo..hi] 进行排序,我们先找一个分界点 p,通过交换元素使得 nums[lo..p-1] 都小于等于 nums[p],且 nums[p+1..hi] 都大于 nums[p],然后递归地去 nums[lo..p-1]nums[p+1..hi] 中寻找新的分界点,最后整个数组就被排序了。

快速排序的代码框架如下:

Java
1
2
3
4
5
6
7
8
9
void sort(int[] nums, int lo, int hi) {
    /****** 前序遍历位置 ******/
    // 通过交换元素构建分界点 p
    int p = partition(nums, lo, hi);
    /************************/

    sort(nums, lo, p - 1);
    sort(nums, p + 1, hi);
}

先构造分界点,然后去左右子数组构造分界点,你看这不就是一个二叉树的前序遍历吗?

再说说归并排序的逻辑,若要对 nums[lo..hi] 进行排序,我们先对 nums[lo..mid] 排序,再对 nums[mid+1..hi] 排序,最后把这两个有序的子数组合并,整个数组就排好序了。

归并排序的代码框架如下:

Java
// 定义:排序 nums[lo..hi]
void sort(int[] nums, int lo, int hi) {
    int mid = (lo + hi) / 2;
    // 排序 nums[lo..mid]
    sort(nums, lo, mid);
    // 排序 nums[mid+1..hi]
    sort(nums, mid + 1, hi);

    /****** 后序位置 ******/
    // 合并 nums[lo..mid] 和 nums[mid+1..hi]
    merge(nums, lo, mid, hi);
    /*********************/
}

先对左右子数组排序,然后合并(类似合并有序链表的逻辑),你看这是不是二叉树的后序遍历框架?另外,这不就是传说中的分治算法嘛,不过如此呀。

如果你一眼就识破这些排序算法的底细,还需要背这些经典算法吗?不需要。你可以手到擒来,从二叉树遍历框架就能扩展出算法了。

说了这么多,旨在说明,二叉树的算法思想的运用广泛,甚至可以说,只要涉及递归,都可以抽象成二叉树的问题。

Java
class Solution {
    List<List<Integer>> res = new LinkedList<>();
/* 主函数,输入一组不重复的数字,返回它们的全排列 */
List<List<Integer>> permute(int[] nums) {
    // 记录「路径」
    LinkedList<Integer> track = new LinkedList<>();
    // 「路径」中的元素会被标记为 true,避免重复使用
    boolean[] used = new boolean[nums.length];

    backtrack(nums, track, used);
    return res;
}

// 路径:记录在 track 中
// 选择列表:nums 中不存在于 track 的那些元素(used[i] 为 false)
// 结束条件:nums 中的元素全都在 track 中出现
void backtrack(int[] nums, LinkedList<Integer> track, boolean[] used) {
    // 触发结束条件
    if (track.size() == nums.length) {
        res.add(new LinkedList(track));
        return;
    }

    for (int i = 0; i < nums.length; i++) {
        // 排除不合法的选择
        if (used[i]) {
            // nums[i] 已经在 track 中,跳过
            continue;
        }
        // 做选择
        track.add(nums[i]);
        used[i] = true;
        // 进入下一层决策树
        backtrack(nums, track, used);
        // 取消选择
        track.removeLast();
        used[i] = false;
    }
}
    }
C
1
2
3
4
5
6
7
/*a generalization of preorder traversal*/
void DFS(Vertex V)
{   
    visited[ V ] = true;  /*mark this vertex to avoid cycles*/
    for ( each W adjacent to V )
        if ( !visited[ W ] ) DFS( W );
} /*T = O(|E|+|V|) as long as adjacency lists are used*/