LeetCode---3月1日周赛---个人题解

第二题:通过投票对团队排名

题目地址

题目描述

现在有一个特殊的排名系统,依据参赛团队在投票人心中的次序进行排名,每个投票者都需要按从高到低的顺序对参与排名的所有团队进行排位。
排名规则如下:

  • 参赛团队的排名次序依照其所获「排位第一」的票的多少决定。如果存在多个团队并列的情况,将继续考虑其「排位第二」的票的数量。以此类推,直到不再存在并列的情况。
  • 如果在考虑完所有投票情况后仍然出现并列现象,则根据团队字母的字母顺序进行排名。

给你一个字符串数组 votes 代表全体投票者给出的排位情况,请你根据上述排名规则对所有参赛团队进行排名。

请你返回能表示按排名系统 排序后 的所有团队排名的字符串

样例1

输入:votes = [“ABC”,“ACB”,“ABC”,“ACB”,“ACB”]
输出:“ACB”
解释:A 队获得五票「排位第一」,没有其他队获得「排位第一」,所以 A 队排名第一。
B 队获得两票「排位第二」,三票「排位第三」。
C 队获得三票「排位第二」,两票「排位第三」。
由于 C 队「排位第二」的票数较多,所以 C 队排第二,B 队排第三。

思路

就是根据排位的先后顺序进行排序,使用一个二维数组将对应排位的票数存起来,然后依此为依据进行排序。

使用并重写java中sort函数

java实现代码如下
public class Solution{
     public String rankTeams(String[] votes) {
        int len = votes.length;//投票的人数
        int teamNum = votes[0].length();//队伍的数量
        if(len == 1 || teamNum == 1)
            return votes[0];
        int[][] num = new int[26][teamNum];//用来放置每个队伍对应的排位的投票数
        for(int i = 0;i < len;i++){
            for(int j = 0;j < teamNum;j++)
                num[votes[i].charAt(j)-65][j]++;//对应的排位投票数加一
        }
        
        Character[] ch = new Character[teamNum];//重写sort的话需要传递一个对象参数
        for(int i = 0;i < teamNum;i++)
            ch[i] = new Character(votes[0].charAt(i));
            
        //下面是主要部分,使用重写的sort函数
        Arrays.sort(ch,new Comparator<Character>(){
           @Override
           public int compare(Character s1,Character s2){
               for(int i = 0;i < teamNum;i++){
                    if(num[s1-65][i] > num[s2-65][i])//如果当前排位投票数大,则放到前面
                       return -1;//返回-1是按照降序排列
                    if(num[s1-65][i] < num[s2-65][i])
                        return 1;
               }
               return s1-s2;//如果排名相等的话,按照字典序排列
           }
        });
        char[] ans = new char[teamNum];
        for(int i = 0;i < teamNum;i++)
            ans[i] = ch[i];
        
        return String.valueOf(ans); 
     }
}

第三题 二叉树中的列表

题目地址

题目描述

给你一棵以 root 为根的二叉树和一个 head 为第一个节点的链表。

如果在二叉树中,存在一条一直向下的路径,且每个点的数值恰好一一对应以 head 为首的链表中每个节点的值,那么请你返回 True ,否则返回 False 。

一直向下的路径的意思是:从树中某个节点开始,一直连续向下的路径。

样例:

  • 输入:head = [4,2,8], root = [1,4,4,null,2,2,null,1,null,6,8,null,null,null,null,1,3]
  • 输出:true
  • 解释:树中蓝色的节点构成了与链表对应的子路径。
思路

使用两次dfs,第一次找到树中和链表头结点相同的节点,然后对每个节点进行一个dfs,若找到则返回true,否则返回false。

java实现代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSubPath(ListNode head, TreeNode root) {
        if(root == null) //第一次dfs如果没有匹配到和头结点相同的节点,就应该返回false
            return false;
        if(head.val == root.val){
            boolean ans = help(head.next,root.left)||help(head.next,root.right);//如果找到和头结点相同的树节点,此时进入第二个dfs,
            if(ans)
                return true;
        }
        return isSubPath(head,root.left)||isSubPath(head,root.right);
    }
    
    public boolean help(ListNode head,TreeNode root){
        if(head == null)
            return true;//链表走到最后说明存在路径,返回true
        if(root == null)
            return false;//树走到最后,说明不存在,返回false
        if(root.val != head.val)
            return false;
        return help(head.next,root.left)||help(head.next,root.right);
    }
    
}

第四题 使得网格图至少有一条路径的最小代价

题目地址

题目描述

给你一个 m x n 的网格图 grid grid 中每个格子都有一个数字,对应着从该格子出发下一步走的方向。 grid[i][j] 中的数字可能为以下几种情况:

  1. 下一步往右走,也就是你会从 grid[i][j] 走到 grid[i][j + 1]
  2. 下一步往左走,也就是你会从 grid[i][j] 走到 grid[i][j - 1]
  3. 下一步往下走,也就是你会从 grid[i][j] 走到 grid[i + 1][j]
  4. 下一步往上走,也就是你会从 grid[i][j] 走到 grid[i - 1][j]

注意网格图中可能会有 无效数字 ,因为它们可能指向 grid 以外的区域。

一开始,你会从最左上角的格子 (0,0) 出发。我们定义一条 有效路径 为从格子 (0,0) 出发,每一步都顺着数字对应方向走,最终在最右下角的格子 (m - 1, n - 1) 结束的路径。有效路径 不需要是最短路径 。

你可以花费 cost = 1 的代价修改一个格子中的数字,但每个格子中的数字 只能修改一次 。

请你返回让网格图至少有一条有效路径的最小代价。

例子

输入:grid = [[1,1,1,1],[2,2,2,2],[1,1,1,1],[2,2,2,2]]

输出:3

解释:你将从点 (0, 0) 出发。
到达 (3, 3) 的路径为: (0, 0) --> (0, 1) --> (0, 2) --> (0, 3) 花费代价 cost = 1 使方向向下 --> (1, 3) --> (1, 2) --> (1, 1) --> (1, 0) 花费代价 cost = 1 使方向向下 --> (2, 0) --> (2, 1) --> (2, 2) --> (2, 3) 花费代价 cost = 1 使方向向下 --> (3, 3)
总花费为 cost = 3.

思路

参考了LeetCode一些大神的题解。这道题可以利用BFS+记忆化搜索的方法,我们使用一个数组dst[][] 保存起点到当前节点的值,使用一个队列存放以经确定最小cost的点,使用宽度优先遍历的思想,更新dst[][] ,最终我们就可以得到各个节点的最小cost。

java实现代码
import java.util.*;
class Solution {
    public int minCost(int[][] grid) {
        int n = grid.length;
        int m = grid[0].length;
        
        int[][] d = new int[]{{},{0,1},{0,-1},{1,0},{-1,0}};//用来存放节点移动的时候,横纵坐标的变化量
        int[][] dst = new int[n][m];//存放所有点到起点最小的cost
        
        for(int i = 0;i < n;i++)
            Arrays.fill(dst[i],-1);//将初始值设为-1,如果值为-1,则证明没有初始化
        dst[0][0] = 0;
        Queue<int[]> queque = new LinkedList<>();
        queue.offer(new int[]{0,0});//将图像的一个放入队列中
        while(!queue.isEmpty()){
            int x = queue.size();
            for(int i = 0;i < x;i++){
                int[] q = queue.poll();
                if(q[0]==n-1 || q[1] == m-1)//如果到达终点,跳过
                    continue;
                int val = gird[q[0]][q[1]];//val表示当前节点的值
                for(int j = 1;j <= 4;j++){//当前节点向4个方向进行扩展
                    int r = q[0]+d[j][0];//变化后的横坐标
                    int c = q[1]+d[j][1];//变化后的纵坐标
                    if(r>=0 && c>=0 && r<n && c<n){//不能超出边界范围
                        int add = j==val?0:1;
                        if(dst[r][c]==-1 || dst[r][c] > dst[q[0]][q[1]]+add){//更新dst的条件
                        /*
                        *r如果没有初始化,那么就初始化dst[r][c],
                        *否则就判断 dst[r][c] 和 dst[q[0]][q[1]]的大小
                        */
                            dst[r][c] = dst[q[0]][q[1]]+add;
                            queue.offer(r,c);
                        }
                    }
                }
            }
        }
        return dst[n-1][m-1];
        
    }
        
}

你可能感兴趣的:(LeetCode)