【LeetCode两题选手】算法类题目(7.27)

时间:2022-07-23
本文章向大家介绍【LeetCode两题选手】算法类题目(7.27),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

第一题:全排列(回溯)

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/permutations 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:

回溯法 :一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解被确认不是一个解的话(或者至少不是最后一个解),回溯算法会通过在上一步进行一些变化抛弃该解,即回溯并且再次尝试。

使用标记数组来处理填过的数是一个很直观的思路,但是可不可以去掉这个标记数组呢?毕竟标记数组也增加了我们算法的空间复杂度。

答案是可以的,我们可以将题目给定的 n 个数的数组 nums[]划分成左右两个部分,左边的表示已经填过的数,右边表示待填的数,我们在递归搜索的时候只要动态维护这个数组即可。

举个简单的例子,假设我们有 [2, 5, 8, 9, 10] 这 5 个数要填入,已经填到第 3 个位置,已经填了 [8,9] 两个数,那么这个数组目前为 [8, 9 | 2, 5, 10] 这样的状态,分隔符区分了左右两个部分。假设这个位置我们要填 10 这个数,为了维护数组,我们将 2 和 10 交换,即能使得数组继续保持分隔符左边的数已经填过,右边的待填 [8, 9, 10 | 2, 5] 。

作者:LeetCode-Solution 链接:https://leetcode-cn.com/problems/permutations/solution/quan-pai-lie-by-leetcode-solution-2/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

	vector<vector<int>> permute(vector<int>& nums) {
        if(nums.empty()) return {};
        // 存放最后结果
        vector<vector<int>> ans;
        // 存放某一个排列
        vector<int> temp;
        // 判断该数字是否被使用过
        vector<bool> used(nums.size(),false);
        // 进行递归求解
        dfs(ans,temp,used,nums);

        return ans;
    }

    void dfs(vector<vector<int>>& ans,vector<int>& temp,vector<bool>& used,
    const vector<int>& nums)
    {
        // 如果当前排列数组的长度等于输入数组的长度
        // 该排列已完成
        // 将该排列的加入结果中,返回
        if(temp.size()==nums.size())
        {
            ans.push_back(temp);
            return;
        }

        // 循环的进行枚举所有状态
        for(int i=0;i<nums.size();++i)
        {
            // 该数字已经选择过,跳过
            if(used.at(i)) continue;

            // 选择当前数字
            temp.push_back(nums.at(i));
            // 记录该数字已被选择
            used.at(i)=true;
            // 递归选择下一个数字
            dfs(ans,temp,used,nums);
            // 回溯,撤销当前选择
            used.at(i)=false;
            temp.pop_back();
        }
    }

思考

晕,看来要自己去写一下“八皇后问题”了。

题二:二叉搜索树中第K小的元素

给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。

说明: 你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。

示例 1:

输入: root = [3,1,4,null,2], k = 1

   3
  / 
 1   4
  
   2

输出: 1

示例 2:

输入: root = [5,3,6,2,4,null,null,1], k = 3

   	   5
      / 
     3   6
    / 
   2   4
  /
 1

输出: 3

进阶: 如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化 kthSmallest 函数?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

中序遍历二叉搜索树,在遍历的过程中,每经过一个节点将k减1,当k == 0的时候,则找到了第k小的元素(注意边界)。

题解

 void recursion(TreeNode* root,int& res,int& k)
    {
        if(!root)
            return;
        
        recursion(root->left,res,k);
        
        k--;
        if(k == 0)
        {
            res = root->val;
            return;
        }
            
        recursion(root->right,res,k);
    }
    
    int kthSmallest(TreeNode* root, int k) {
        int res;
        recursion(root,res,k);
        
        return res;
    }

思考

关于进阶那块,我觉得可以思考一下伸展树:伸展树,据说比AVL树要简单一些 手植这棵自顶向下伸展树,何时亭亭如盖呢?