首页 > 技术文章 > 【LeetCode997】【哈希表】[Py/C#/Scala/Elixir/Kotlin/Rust/Ruby/Swift/PHP/Java/Go/C++/TS/Erlang/Racket] 一道统计入度出度的简单题目

yhm138 2022-06-24 21:41 原文

解题思路

一道统计入度出度的简单题目
题解地址 https://leetcode.cn/problems/find-the-town-judge/solution/python-by-yhm138_-yezp/
lc997

代码

python3

## 练习使用collections模块的Counter

from collections import Counter 
class Solution:
    def findJudge(self, n: int, trust: List[List[int]]) -> int:
        tmp1=map(lambda x:x[0],trust)
        outDgree=Counter(tmp1)
        tmp2=map(lambda x:x[1],trust)
        inDgree=Counter(tmp2)
        for i in range(1,n+1,1):
            if inDgree[i]==n-1 and outDgree[i]==0:
                return i
        return -1        
        

c#

//熟练掌握Dictionary常用API

using System.Collections.Generic;

public class Solution {
    public int FindJudge(int n, int[][] trust) {
        Dictionary<int,int>inDegree=new Dictionary<int,int>();
        Dictionary<int,int>outDegree=new Dictionary<int,int>();
        trust.Where((ele, index) =>
        {
            
            //Your Logic starts here
            if(!inDegree.ContainsKey(ele[1])){
                inDegree.Add(ele[1],1);
            }
            else{
                inDegree[ele[1]]+=1;
            }
            if(!outDegree.ContainsKey(ele[0])){
                outDegree.Add(ele[0],1);
            }
            else{
                outDegree[ele[0]]+=1;
            }

            //Your Logic ends here
            return false;
        }).Any();

        for(int i=1;i<=n;i++){
            if(!inDegree.ContainsKey(i)){
                inDegree[i]=0;
            }
            if(!outDegree.ContainsKey(i)){
                outDegree[i]=0;
            }
            if(inDegree[i]==n-1 && outDegree[i]==0 ) return i;
        }
        return -1;
    }
}

scala

import scala.collection.mutable._

//统计入度出度,找到第一个满足【inDegrees[i] == n - 1 && outDegrees[i] == 0】的节点,返回标号i
//这里没有用函数式编程范式
object Solution {
    def findJudge(n: Int, trust: Array[Array[Int]]): Int = {
        var inDegree=Map[Int,Int]().withDefaultValue(0);
        var outDegree=Map[Int,Int]().withDefaultValue(0);
        trust.foreach(x=>{
            inDegree(x(1))=inDegree.getOrElse(x(1),0)+1;
            outDegree(x(0))=outDegree.getOrElse(x(0),0)+1;
        });
        for(i<- 1 to n){
            if(inDegree(i)==n-1 && outDegree(i)==0){
                return i;
            }
        }
        -1;
        
    }
}

elixir

# 感谢hexdocs.pm/elixir文档的帮助,我能写出来这份代码很大程度上归功于这份文档写得很详细
# 可以看到我的代码风格,能用API解决的绝不去写模式匹配

defmodule Solution do
  @spec find_judge(n :: integer, trust :: [[integer]]) :: integer
  def find_judge(n, trust) do
    inDegree=trust|> Enum.map(fn x->Enum.at(x,1) end) |> Enum.frequencies()
    outDegree=trust|> Enum.map(fn x->Enum.at(x,0) end) |> Enum.frequencies()
    ans=(1..n)|> Enum.find(fn x->
      # IO.inspect(inDegree)
      # IO.inspect(outDegree)
      ( (n===1 && inDegree[x]===nil)|| (inDegree[x]===n-1) ) && outDegree[x]===nil
     end )
    # IO.inspect(inDegree)
    if (ans===nil) do -1 else ans end
  end
end

kotlin

//JVM语言写起来都差不多
//这个我花了几分钟就写完了
class Solution {
    fun findJudge(n: Int, trust: Array<IntArray>): Int {
        var inDegree = linkedMapOf<Int,Int>();
        var outDegree = linkedMapOf<Int,Int>();
        var key=-1;
        for(i in 0..trust.size-1){
            key=trust[i][0];
            outDegree[key]=outDegree.getOrDefault(key,0)+1;
            key=trust[i][1];
            inDegree[key]=inDegree.getOrDefault(key,0)+1;
        }
        for(i in 1..n){
            if (inDegree.getOrDefault(i,0)==n-1 && outDegree.getOrDefault(i,0)==0){
                return i;
            }
        }
        return -1;
    }
}

rust

// 就是把别人的Rust题解改成HashMap版本的
// 执行用时:24 ms, 在所有 Rust 提交中击败了33.33%的用户
// 内存消耗:2.8 MB, 在所有 Rust 提交中击败了41.67%的用户

use std::collections::HashMap;
impl Solution {
    pub fn find_judge(n: i32, trust: Vec<Vec<i32>>) -> i32 {
        let mut inDegree =HashMap::new();
        let mut outDegree =HashMap::new();
        for t in trust{
            *inDegree.entry(t[1]).or_insert(0) += 1;
            *outDegree.entry(t[0]).or_insert(0) += 1;
        }
        // println!("{:?}", inDegree);
        // println!("{:?}", outDegree);
        
        
        let my_vec:Vec<_> = (0..=n).step_by(1).collect();
        // println!("{:?}", my_vec);
        match my_vec.iter().skip(1).position( |&x| 
               (inDegree.get(&x).cloned().unwrap_or(0)==n-1 && outDegree.get(&x).cloned().unwrap_or(0)==0)
        ){
            Some(i) => i as i32 + 1,
            None    => -1,
        }
        
    }
}

ruby

# @param {Integer} n
# @param {Integer[][]} trust
# @return {Integer}
def find_judge(n, trust)
    inDegree = Hash.new(0)  #缺省value是0
    outDegree = Hash.new(0) #缺省value是0
    trust.each_with_index do |t|
        inDegree[t[1]]+=1
        outDegree[t[0]]+=1
    end 
    for i in 1..n
        if(inDegree[i]==n-1 && outDegree[i]==0) then return i end
    end
    return -1
end



# 下面是草稿

# tmp1 = trust.map do |n|
#     n[0] 
# end
# puts tmp1
# tmp2=trust.map { |item| item[1]}

# puts "#{index}. #{fruit}"

swift

// import Cocoa   //我瞎写的,Cocoa是OS X和 iOS操作系统的程序的运行环境。

class Solution {
    func findJudge(_ n: Int, _ trust: [[Int]]) -> Int {
        var inDegree = [Int: Int]();
        var outDegree = [Int: Int]();
        for (index, ele) in trust.enumerated() {
            // print("\(index):\(ele)");
            inDegree[ele[1],default: 0]+=1;
            outDegree[ele[0],default: 0]+=1;
        }
        for i in 1...n {
            if (inDegree[i,default: 0]==n-1 && outDegree[i,default: 0]==0  ) {
                return i;
            }
        }
        return -1;
    }
}

php

// $符号也太多了,比shell编程用到的$符号还多
class Solution {

    /**
     * @param Integer $n
     * @param Integer[][] $trust
     * @return Integer
     */
    function findJudge($n, $trust) {
        // $inDegree=array();
        // $outDegree=array();
        $inDegree=array_count_values(array_map(fn($x):int => $x[1] , $trust));
        $outDegree=array_count_values(array_map(fn($x):int => $x[0] , $trust));
        // var_dump($inDegree);
        for ($x=1; $x<=$n; $x++) {
            if($inDegree[$x]==$n-1 && $outDegree[$x]==0 ) return $x;
        } 
        return -1;
    }
}


//草稿
// print_r(array_map(fn($value): int => $value * 2, range(1, 5)));

java

//这份代码写得确实不好,抱歉

import java.util.*;

public class Solution {
    public int findJudge(int n, int[][] trust) {
        Map < Integer, Integer > inDegree = new LinkedHashMap < Integer, Integer > ();
        Map < Integer, Integer > outDegree = new LinkedHashMap < Integer, Integer > ();
        for(int [] ele:trust){
            Integer key1=Integer.valueOf(ele[1]);
            inDegree.put(key1,inDegree.getOrDefault(key1,0)+1);
            Integer key2=Integer.valueOf(ele[0]);
            outDegree.put(key2,outDegree.getOrDefault(key2,0)+1);
        } 
        for(int i=1;i<=n;i++){
            if(inDegree.getOrDefault(i,0)==n-1 && outDegree.getOrDefault(i,0)==0  ){
                return i;
            }
        }
        return -1;
    }
}



//下面是草稿

// import java.util.ArrayList;
// import java.util.List;
// import java.util.function.BiConsumer;
// import java.util.function.Consumer;
// import java.util.ArrayList;
// import java.util.Arrays;
// import java.util.stream.Collectors;


// //大佬写的工具类
// class LambadaToolsa {
//     /**
//      * 利用BiConsumer实现foreach循环支持index
//      *
//      * @param biConsumer
//      * @param <T>
//      * @return
//      */
//     public static <T> Consumer<T> forEachWithIndex(BiConsumer<T, Integer> biConsumer) {
//         /*这里说明一下,我们每次传入forEach都是一个重新实例化的Consumer对象,在lambada表达式中我们无法对int进行++操作,
//         我们模拟AtomicInteger对象,写个getAndIncrement方法,不能直接使用AtomicInteger哦*/
//         class IncrementInt{
//             int i = 0;
//             public int getAndIncrement(){
//                 return i++;
//             }
//         }
//         IncrementInt incrementInt = new IncrementInt();
//         return t -> biConsumer.accept(t, incrementInt.getAndIncrement());
//     }
// }

golang

//在golang中练习字典用法,写得略丑,抱歉
//golang中变量定义了就要使用,不然编译阶段就会报错
//golang的 }else 在同一行,else不能新起一行
//golang中没有while    应该这么写: for count < 100 {  }


import (
    "fmt"
);

func findJudge(n int, trust [][]int) int {
    var inDegree= make(map[int]int);
    var outDegree= make(map[int]int);

    for _,ele :=range trust{
        if _,ok := inDegree[ele[1]];ok{
            inDegree[ele[1]]+=1;
        }else{
            inDegree[ele[1]]=1;
        }
        if  _,ok := outDegree[ele[0]];ok{
            outDegree[ele[0]]+=1;
        }else{
            outDegree[ele[0]]=1;
        }
    }
    for i:=1;i<=n;i++{
        if _,ok := inDegree[i];!ok{
            inDegree[i]=0;
        }
        if _,ok := outDegree[i];!ok{
            outDegree[i]=0;
        }
        if outDegree[i]==0 && inDegree[i]==n-1 {
            return i;
        }

    }

    return -1;
}

cpp

//瞎写的,这份代码挺不安全的,最好不要将这样的代码用在你的业务中
//Don't use operator[] with the STL map containers. They construct the value if it is not present. 
//Use .at() ,if not present, it will throw exception
using i64 = long long;
constexpr i64 inf = 1E18;

class Solution {
public:
    int findJudge(int n, vector<vector<int>>& trust) {
        std::unordered_map<int, int>  inDegree,outDegree;
        for(const auto &t : trust ){
            inDegree[t[1]]+=1;
            outDegree[t[0]]+=1;
        }
        for(int i=1;i<=n;i++){
            if (inDegree[i]==n-1 && outDegree[i]==0){
                return i;
            }
        }
        return -1;
    }
};


//下面是一些草稿
// std::vector<int> s1;
// auto addTwoElement = [&](int l,int r) {
//     s1.push_back(l);
//     s1.push_back(r);
// };
// addTwoElement(3,5);
// for (auto ele : s1)   std::cout << ele << ' ';

typescript

//TS是JavaScript的超集,具有可选的类型并可以编译为纯js。从技术上讲TypeScript就是具有静态类型的 JavaScript 。
//注意运算符优先级,这里我被坑了一下  ?? == = + 这些运算符的优先级你知道吗?


function findJudge(n: number, trust: number[][]): number {
    let inDegree  : {[key:number]:number} = {};
    let outDegree : {[key:number]:number} = {};
    trust.forEach( (ele,index)=>{
        outDegree[ele[0]]=(outDegree[ele[0]]??0)+1;
        inDegree[ele[1]]=(inDegree[ele[1]]??0)+1;
    });
    // console.log(outDegree[1]);
    // console.log(outDegree['1']);

    const One2n_Range=Array.from(Array(n).keys()).map(x=>1*x+1);  //我没找到Range
    for(let x of One2n_Range){
        if( ((outDegree[x]??0)==0) && ((inDegree[x]??0)==n-1) ){   
            return x;
        }
    }
    return -1;
};

erlang

%怎么折磨编程菜鸟,给他为数不多的资料,让他持续写3~5小时的Erlang
%这份代码2022-06-24我提交的时候是双百,,,
%可能写Erlang的真的不多,几乎就是存粹的FP,写各种模式匹配
-spec find_judge(N :: integer(), Trust :: [[integer()]]) -> integer().
tally([]) -> [];
tally(L) ->  compress2(lists:sort(L)).

compress2([]) -> [];
compress2([H|T]) ->
    helper2(T, H, 1).

helper2([H|T], H, Count) ->
    helper2(T, H, Count+1);
helper2([H|T], C, Count) ->
    [{C, Count}|helper2(T, H, 1)];
helper2([], C, Count) ->
    [{C, Count}].   


find_judge(N, Trust) ->

    Fun0=fun(V1) -> lists:nth(1,V1) end, 
    Tmp1=lists:map(Fun0,Trust),
    OutDegree=orddict:from_list(tally(Tmp1)),
    
    Fun1=fun(V1) -> lists:nth(2,V1) end, 
    Tmp2=lists:map(Fun1,Trust),
    InDegree=orddict:from_list(tally(Tmp2)),

    % io:write(tally([3,4,3,4,3])),
    % io:write(InDegree),
    % io:write(OutDegree),

     case lists:dropwhile(fun(X) ->
    %   io:write(X),
    %   io:write(orddict:find(X,InDegree)),
    %    io:write(orddict:find(X,OutDegree)),
    %   a=orddict:find(X,InDegree),
    %   b=orddict:find(X,OutDegree),
      not(
          (
              ( orddict:find(X,InDegree)=/=error   andalso    lists:nth(2,tuple_to_list(orddict:find(X,InDegree)))==N-1 ) or
              ( orddict:find(X,InDegree)=:=error   andalso    N==1)
          )andalso
          (orddict:find(X,OutDegree)=:=error)
      )
      end, lists:seq(1,N,1)) of
       [] -> -1;
       [X | _] -> X
    end.

 



%草稿
%   Fun0=fun(K,V1) -> lists:nth(1,V1) end, 
%   Tmp1=maps:map(Fun0,Trust),
%   io:write(Tmp1).

racket

; Racket是在基于Scheme发展起来的,当然也是Lisp的一种方言。
; 下面的代码并不是纯粹的FP   可以看到我`hash-set!` 和 `set!` 满天飞
; 怎么折磨写MATLAB数圆括号的人?  让TA来写Racket
; expected a procedure that can be applied to arguments 是因为你使用了冗余的圆括号
; 那什么,,,2022-06-30这份AC代码的执行用时和内存消耗都是33.33%
; 我这份Racket代码确实没有题解区的另外2份Racket代码写得好


(define/contract (find-judge N trust)
  (-> exact-integer? (listof (listof exact-integer?)) exact-integer?)
    (define (func0 my_list) (list-ref my_list 0))
    (define (func1 my_list) (list-ref my_list 1))
    (define tmp0 make-list)
    (define tmp1 make-list)
    (set! tmp0 (map func0 trust))
    (set! tmp1 (map func1 trust))
    ; (displayln tmp0)
    
    (define inDegree (make-hasheq))
    (for ([i (in-range 1 (add1 N))])   (hash-set! inDegree i 0)   )
    (define outDegree (make-hasheq))
    (for ([i (in-range 1 (add1 N))])   (hash-set! outDegree i 0)   )
    
    (for-each
        (lambda (ele) (
            hash-set! outDegree ele (+ (hash-ref outDegree ele) 1) 
        )) 
    tmp0)

    (for-each
        (lambda (ele) (
            hash-set! inDegree ele (+ (hash-ref inDegree ele) 1) 
        )) 
    tmp1)
    
    ;  (displayln outDegree)

    (define x -1)
    (for ([i (in-range 1 (add1 N))])
        (
            cond([ and  (= (- N 1) (hash-ref inDegree i))  (= 0 (hash-ref outDegree i))    ]
                (set! x i)
            )
        )
    )

    (cond [(= -1 x) -1] [else x])  ;废话大师
)

各语言执行用时和内存消耗比较

我看了下提交记录,Scala最慢,,,Rust(和Java)最快,,,符合预期
image.png

image.png

推荐阅读