J20250704 算法题5道

题目一览:

606. 根据二叉树创建字符串 - 力扣(LeetCode)

506. 相对名次 - 力扣(LeetCode)

1. 两数之和 - 力扣(LeetCode)

100. 相同的树 - 力扣(LeetCode)

101. 对称二叉树 - 力扣(LeetCode)

这是周一截止到今天周五的,这次选的题目都比较简单。大部分都和二叉树用dfs 解题有关(因为前一整子学了这些,刚好就再写一遍),有一道是关于最近学的堆排序。

题解:

1. 根据二叉树创建字符串

给你二叉树的根节点 root ,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。

空节点使用一对空括号对 "()" 表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。

解: ++这道题的关键是明白什么时候存放root.val ,什么时候存放 "()""( "" )"++

1) 创建StringBuilde类型的对象stringbuilder ,之后得到结果都可以通过append操作一步步添加到stringbuilder中。

**2)**遍历二叉树(递归):

a. 需要分别判断左子树和右子树的情况,当 root 不为空,则将 root.val 放到stringbuilder中。

b. 再去看左子树情况 ------> 判断 root.left 是否为空,不为空就将"( " 放到stringbuilder中 ,代表有左子树,再将左子树的根放入函数进行递归 ,重复上面的操作。而如果 root.left 为空, 就需要判断右子树,右子树也为空,则直接返回,不为空则将"()" 放入stringbuilder再返回。

c. 判断右子树的情况的代码逻辑则和左子树一致。唯一不同的是如果判断右子树为空的话,不用再去判断左子树是否为空 ,而是直接返回

d. 最后得到结果stringbuilder,输出即可

注意:在每次递归返回时," )"都会放入stringbuilder。不需要在其他地方再加多余的 ")"。(不太明白的话可以看看代码理解)

代码:

java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public String tree2str(TreeNode root) { 
        StringBuilder stringBuilder = new StringBuilder();
        tree2strChild(root,stringBuilder);
        return stringBuilder.toString();
    }

    public void tree2strChild(TreeNode root,StringBuilder stringBuilder){
        if(root == null){
            return;
        }
        stringBuilder.append(root.val);
        //判断左子树的情况
        if(root.left!=null){
            stringBuilder.append("(");
            tree2strChild(root.left,stringBuilder);
            stringBuilder.append(")");
        }else{
            if(root.right!=null){
                stringBuilder.append("()");
            }else{
                return;
            }
        }
        //判断右子树的情况
        if(root.right!=null){
            stringBuilder.append("(");
            tree2strChild(root.right,stringBuilder);
            stringBuilder.append(")");
        } else{
            return;
        }
    }
}

2. 相对名次

给你一个长度为 n 的整数数组 score ,其中 score[i] 是第 i 位运动员在比赛中的得分。所有得分都 互不相同

运动员将根据得分 决定名次 ,其中名次第 1 的运动员得分最高,名次第 2 的运动员得分第 2 高,依此类推。运动员的名次决定了他们的获奖情况:

  • 名次第 1 的运动员获金牌 "Gold Medal"
  • 名次第 2 的运动员获银牌 "Silver Medal"
  • 名次第 3 的运动员获铜牌 "Bronze Medal"
  • 从名次第 4 到第 n 的运动员,只能获得他们的名次编号(即,名次第 x 的运动员获得编号 "x")。

使用长度为 n 的数组 answer 返回获奖,其中 answer[i] 是第 i 位运动员的获奖情况。

解: 这道题的思路很简单,首先要得到名次,就需要排序 。然后对照原数组,按照对应的位置给出排名情况 。一开始写的是得到一个排完序的数组,然后两个for循环嵌套,一个个对照,结果放进answer数组,但是这样做会超出时间限制,时间复杂度为O(n^2),所以后面又用到了哈希表, 这样就可以快速得到对应键值的在原数组的下标

1)这里为了巩固学习的新知识,排序采用了堆排序

a. 首先将原数组复制一份,再将复制的数组变成小根堆

b. 每次将堆顶元素和最后一个元素交换,再将堆数组的长度减1,把其余的部分再进行siftdown,变成小根堆后,重复交换操作和长度减1,以及siftdown操作,以此完成堆排序。

2)哈希表存好原数组 以及对应的原始下标 ,将排完序的数组的值循环给哈希表,得到原始位置,将名次按照原始位置放入answer数组中即可。

代码:

java 复制代码
//1.用堆排序,将数组排成降序
//2.将在ret数组中找到score数组中数据所在的下标名次就是i+1
//3.创建answer数组,将对比出来的结果依次放入answers数组

class Solution {
    int[] ret;

    public void siftDown(int parent,int usedSize){
        int child = 2 * parent + 1;
        
        while(child < usedSize){
            //child是否需要换位置
            if(child + 1 < usedSize && ret[child] > ret[child+1]){
                child++;
            }
            if(ret[child] < ret[parent]){
                int temp;
                temp = ret[child];
                ret[child] = ret[parent];
                ret[parent] = temp;
                parent = child;
                child = 2 * parent + 1;
            }else{
                break;
            }
 
        }
    }

    public void heapSort(int end){
        while(end > 0){
            int temp;
            temp = ret[end];
            ret[end] = ret[0];
            ret[0] = temp;
            siftDown(0,end);
            end--;
        }
      
    }

    public String[] findRelativeRanks(int[] score) {

        //为防止超时(一开始使用两个for循环嵌套得answer数组超时了...),使用哈希表
        Map<Integer,Integer> scoreIndexMap = new HashMap<>();

        for(int i = 0;i < score.length;i++){
            scoreIndexMap.put(score[i],i);
        }

        String[] answer = new String[score.length]; 
        ret = Arrays.copyOf(score,score.length);
        int child = ret.length-1;
        int parent = (child-1)/2;
        for(int i = parent ; i >= 0 ; i--){
            siftDown(i,ret.length);
        }
        //创建好小根堆后,使用堆排序(降序)
        heapSort(score.length-1);

        for(int i = 0;i < ret.length;i++){
            //找到对应位置
            int originalIndex = scoreIndexMap.get(ret[i]);
                if(i == 0){
                    answer[originalIndex] = "Gold Medal";
                }else if(i == 1){
                    answer[originalIndex] = "Silver Medal";
                }else if(i == 2){
                    answer[originalIndex] = "Bronze Medal";
                }else{
                    answer[originalIndex] = String.valueOf(i+1);
                }
            
        }
        return answer;
    }
}

3.两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。

你可以按任意顺序返回答案。

解:这里一开始用的是暴力解法,两个循环嵌套遍历即可。降低时间复杂度可以使用哈希表,提供利用哈希表的解法。

1)遍历nums数组,将target - nums[ i ] 给哈希表,查看哈希表是否存在对应的数,如果咩有就将num[ i ] 和 i 放进哈希表,然后继续判断。

这里的巧妙就在于哈希表并没有一开始就放入数据,而是在遍历过程一步步将数据放入哈希表。

代码:

java 复制代码
class Solution {
    public int[] twoSum(int[] nums, int target) {
       //为了降低时间复杂度,采用哈希表
       Map<Integer,Integer> hashtable =new HashMap<>();
       for(int i = 0;i<nums.length;i++){
        //在哈希表中查找是否存在target-nums[i],如果有就把位置返回
        if(hashtable.containsKey(target - nums[i])){
            return new int[]{hashtable.get(target-nums[i]),i};
        }
        hashtable.put(nums[i],i);
       }
       return new int[0];
    }
}

4.相同的树

给你两棵二叉树的根节点 pq ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

解: ++弄清true和false的情况,同时遍历两棵树即可。++

1)true:

a. 两颗树都为null

b. 节点的值相同(++如果节点的值相同,则可以进行下一步,而不是返回true,最终返回true还是要看节点是否同时到了null++)

2)false:

a. 一颗树为空,另一棵树不为空

b. 节点的值不相同

3)最后返回 左子树的比较情况&&右子树的比较情况

代码:

java 复制代码
class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if (p == null && q == null) {
            return true;
        } else if (p == null || q == null) {
            return false;
        } else if (p.val != q.val) {
            return false;
        } else {
            return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
        }
    }
}

5.对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

**解:**关键在于找到判断轴对称的方法,代码应该怎么写。(和第4题差不多思想,直接看代码也可)

1)先判断root.left 和root.right 是否相等,相等则继续向下探查,直到出现null 或者二者数值不同时返回true或者false(如果root为null,则直接返回true)

2)再通过递归,root.left作为L,root.right作为R,判断L.left 和 R.right是否相等,以及L.right 和 R.left 是否相等

3)true和false的情况和第4题差不多,可以看代码理解,最后返回 judge(L.left,R.right) && judge(L.right,R.left)

代码:

java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean judge(TreeNode L,TreeNode R){
        if(L == null && R == null){
            return true;
        }else if(L != null && R == null || L == null && R != null){
            return false;
        }else if(L.val != R.val){
            return false;
        }
        //判断对称
        return judge(L.left,R.right) && judge(L.right,R.left);
    }

    public boolean isSymmetric(TreeNode root) {
        if(root == null){
            return true;
        }
        return judge(root.left,root.right);
    }
}

OK,就先这样