ビッグデータの一般的なインタビューアルゴリズム

記事ディレクトリ

1.大量データ処理

1. 100Gを超えるサイズのログファイルを提供します。IPアドレスはログに保存され、アルゴリズムは最も多く発生するIPアドレスを見つけるように設計されています

  • 100Gファイルは大きすぎると感じます。コンピューターのメモリは通常4G程度なので、一度に大量の情報をメモリに読み込むことはできないため、100コピーに分割する必要があります。IPアドレスは長い文字列です、整数%100に変換できるため、係数値が0〜99の範囲になり、同じ係数値を持つIPアドレスがすべて同じファイルに割り当てられるため、次のように使用できます。ハッシュテーブルは、各ファイルで最も多いIPアドレスをカウントし、最後に100個のIPの中で最大のIPを比較します。

2.前の質問と同じ条件で、上位kのIPを見つける方法は?

  • ヒープソーティングの使用にすぐに反応するには、上位IPが必要であることがわかります。ここでのヒープソーティングは、小さなヒープの構築に注意を払う必要があります。大きなヒープを構築する場合、ヒープの一番上の要素が最大であることのみを確認できます。最大のIP

3. 100億の整数が与えられると、設計アルゴリズムは1回だけ現れる整数を見つけます

  • 整数は符号付きと符号なしに分けられます。符号付き数値の値は-2147483648、2147483648 は-21億から+21億、符号なし数値の範囲は 0、4294967296は0から42億ですが、 100億の整数、1回だけ現れる整数を見つけるため、ハッシュテーブルの考え方を使用する必要がありますが、42億* 4Bは約16Gであるため、整数配列を定義しない方がよいので、大きな配列を作成します。ここでは、ビットマップを使用して、ビットを使用して数値が存在しないことを示すことができます。存在しないことは0として表され、1つの発生は1として表され、複数の発生は別のビットによって表されます。配列のサイズを元のサイズの1/16に減らすことができます。もう1つの問題は、この配列の定義方法です。正の数は簡単に定義できます。負の数の場合は、32ビットのすべて1(-1)を使用してXORできます。または、正の数と同じ位置をとり、この時点で2次元配列を定義します。その半分は正の数、負の数の半分はすべて同じ行にあります。このとき、1Gのスペースを使用してこの問題を解決できます。
  • 拡張:面接担当者がここに500M以下のスペースしかないと尋ねた場合はどうなりますか?
  • セグメンテーションの同じ考え方が採用されていますが、ここでは数値の範囲で直接セグメント化できると思います。500Mのメモリがあれば、1回カットできます。現時点で、これを1回だけ見つける可能性が50%ある場合一度現れる数はより効率的かもしれません

4.それぞれ100億クエリの2つのファイルがある場合、1Gのメモリしかありません。2つのファイルの共通部分を見つけ、正確なアルゴリズムと近似アルゴリズムをそれぞれ与える方法

  • 2つのドキュメントの共通部分を検索します。このアルゴリズムは比較に使用する必要があります。両方のドキュメントを100コピーに分割し、1つのドキュメントの1つのドキュメントを他のドキュメントの100コピーと比較するとします。効率が低すぎるので、最初の質問の考え方を借りて係数をとることができるので、2つのファイルを同じ値で比較するだけでよく、それらが同じである場合は、

5.要素の削除操作をサポートするようにBloomFilterを拡張するにはどうすればよいですか?

  • BloomFilter(ブルームフィルターはビットベクトルまたはビット配列です。関連するブルームフィルターの導入を自分で確認できます)は、要素の削除操作をサポートしていません。これは、ハッシュの競合(つまり、異なるハッシュ関数によって計算される)が発生する可能性があるためです。位置は同じビットを指します)、そのため、ビットを変更すると他の要素の判断に影響を与える可能性があります。ここで、スマートポインターを使用したsharedptrのアイデアに従って解決できます。つまり、「参照カウント」、cSountカウンターを追加します。このビットが要素を表す場合は、++カウントし、このビットが表す要素が削除されるたびにカウントするようにします。これにより、カウントが0の場合にのみ、この位置を0に設定して削除を完了します。操作

6.数千のファイルの場合、各ファイルサイズは1K〜100Mであり、nワードの場合、設計アルゴリズムは各ワードに対して彼を含むファイルを検出し、100Kメモリのみ

  • ブルームフィルターを使用して、ファイルにこれらのnワードが含まれているかどうかを判断して、nブルームフィルターを生成し、それらを外部ストレージに配置できます。ファイル内にいるときはいつでも、これらのnワードを含むファイル情報を事前に定義します対応する単語が見つかったら、info内の対応する単語の場所にこのファイルの情報を書き込みます。100kのメモリしかありません。この100kのメモリの一部はブルームフィルターを格納するために使用され、ファイルの一部を格納できます。最小ファイルサイズが100kであるため、あなたはそれを50kの小さなファイルに分割しようとすることができ、各ファイルは大きなファイルでマークされているので、ブルームフィルターと小さなファイルを毎回読み、ファイルに対応する単語がある場合は、情報でそれをマークします属している大きなファイルの情報で、そうでない場合は、次のブルームフィルターを読み取ります。すべてのブルームフィルターを使用したら、次のファイルを読み取り、すべてのファイルがトラバースされるまで上記の手順を繰り返します。

7. N個の英語の単語を含む辞書があります。次に、任意に文字列を指定し、この文字列を含むすべての英語の単語を検索するアルゴリズムを設計します

  • まず、単語に文字列が含まれているかどうかを判断するには、instr関数を使用できます。この問題では、文字列のプレフィックスが検索対象の単語と同じである場合、辞書ツリーを使用して検索できますが、N個の英語の単語を想定できます。非常に大きく、ファイルに入力して、毎回決まった数の単語だけを読んで判断します。
  • 概要:このようなビッグデータの問題については、通常、配列の長さを法とするハッシュ分割を使用してデータを適切な場所に割り当て、同時に大きなファイルを小さなファイルに分割します。これは、 IPアドレスの丸めやハッシュセグメンテーションの実行、内部要素の操作など、他の数値を比較します。BloomFilterを使用して、コレクション内の要素の存在を確認します

2.データ構造

1.バブルソート

  • アルゴリズムのアイデア:
  • 1.シーケンス内のすべての要素をペアで比較し、最大のものを最後に配置します
  • 2.残りのシーケンスのすべての要素をペアで比較し、最大のものを最後に配置します
  • 3.番号が1つだけになるまで、2番目のステップを繰り返します。
	/**
     * 冒泡排序:两两比较,大者交换位置,则每一轮循环结束后最大的数就会移动到最后
     * 时间复杂度为O(n^2) 空间复杂度为O(1)
     * @param arr
     */
    private static void bubbleSort(int[] arr){
    
    
        //外层循环length-1次
        for (int i = 0; i < arr.length-1; i++) {
    
    
            //外层每循环一次最后都会排好一个数
            //所以内层循环length-1-i次
            for (int j = 0; j < arr.length-1-i; j++) {
    
    
                if(arr[j]>arr[j+1]){
    
    
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }	
	}

2.バイナリ検索

  • 1.アルゴリズムの概念
  • 二分探索アルゴリズムは、二分探索とも呼ばれ、二分探索は、配列された配列内の特定の要素を見つけるための探索アルゴリズムです。このアルゴリズムは、配列された配列に基づいていることに注意してください
  • 2.アルゴリズムのアイデア
  • 1)配列の真ん中の要素から検索を開始しますが、真ん中の要素がたまたま見つかった場合、検索は終了します
  • 2)特定の要素が中央の要素より大きいまたは小さい場合、中央の要素より大きいまたは小さい配列の半分を検索し、最初と同じように中央の要素から比較を開始します。
  • 3)あるステップで配列が空の場合、それが見つからないことを意味します
  • 4)この検索アルゴリズムは、比較のたびに検索範囲を半分に減らします
//时间复杂度为O(log n)
public static int binarySearch(int[] srcArray,int des){
    
    
        int low = 0;
        int height = srcArray.length-1;
        while (low<=height){
    
    
            int middle = (low+height)/2;
            if(des==srcArray[middle]){
    
    
                return middle;
            }else if(des < srcArray[middle]){
    
    
                height = middle-1;
            }else {
    
    
                low = middle+1;
            }
        }
        return -1;
 }

3.二分探索を達成するための再帰的方法

public static int binarySearch(int[] dataset,int data,int beginIndex,int endIndex){
    
    
        int midIndex=(beginIndex+endIndex)/2;
        if(data<dataset[beginIndex] || data>dataset[endIndex] || beginIndex>endIndex){
    
    
            return -1;
        }
        if (data<dataset[midIndex]){
    
    
            return binarySearch(dataset,data,beginIndex,midIndex-1);
        }else if(data>dataset[midIndex]){
    
    
            return binarySearch(dataset,data,midIndex+1,endIndex);
        }else {
    
    
            return midIndex;
        }
}

4.単一のリンクリストの反転

class ListNode{
    
    
	int val;
	ListNode next;
	ListNode(int x){
    
    
		val = x;
	}
}

public static ListNode reverseList(ListNode head){
    
    
	ListNode prev = null;
	while(head != null){
    
    
		ListNode temp = head.next;
		head.next=prev;
		prev=head;
		head=temp;
	}
	return prev;
}

5.挿入ソート

  • 1.最初は、最初のレコードはそれ自体で順序付けられたシーケンスを形成し、残りのレコードは無秩序なレコードであると想定されています
  • 2.次に、2番目のレコードから始めて、現在処理されているレコードを、レコードのサイズに従って順番にその前に挿入します。
  • 3.最後のレコードが順序付けされたシーケンスに挿入されるまで
public static void insertSort(int[] a){
    
    
	int temp;
	for(int i=1;i<a.length;i++){
    
    
		for(int j=i;j>0;j--){
    
    
			if(a[j-1]>a[j]){
    
    
				temp=a[j-1];
				a[j-1]=a[j];
				a[j]=temp;
			}
		}
	}
}

6.ソートを選択します

  • 最小または最大を選択
  • 1)指定されたレコードのセットについて、最初の比較の後に最小のレコードが取得され、その後、レコードは最初のレコードの位置と交換されます
  • 2)次に、最初のレコードを除く他のレコードの2回目の比較を実行し、最小のレコードを取得して、2番目のレコードと位置を交換します
  • 3)比較するレコードが1つだけになるまでプロセスを繰り返します
public static void selectSort(int[] a){
    
    
        if (a==null || a.length<=0){
    
    
            return;
        }
        for (int i = 0; i < a.length; i++) {
    
    
            int min = i;
            for (int j = i+1; j <a.length ; j++) {
    
    
                if(a[j]<a[min]){
    
    
                    min=j;
                }
            }
            if(i!=min){
    
    
                int temp = a[min];
                a[min] = a[i];
                a[i] = temp;
            }
        }
    }

7.キュー:シンプルなデータ構造、採用されたスケジューリング戦略は先入れ先出しです

8.二分木の概念と特徴

  • 1.二分木の概念

  • バイナリツリーは非常に重要なデータ構造です。配列とリンクリストの特性を同時に備えています。配列のようにすばやく検索でき、リンクリストのようにすばやく追加することもできます。しかし、独自の欠点があります。削除操作が複雑です。いわゆるバイナリツリーレイヤーの数は深さです。特定のバイナリツリー分類は次のとおりです。

  • バイナリツリー:ノードごとに最大2つのサブツリーを持つ順序付きツリーです。バイナリツリーを使用する場合、データはノードにランダムに挿入されません。ノードの左の子ノードのキー値は、このノード、右の子ノードより小さくなければなりませんキー値はこのノード以上でなければならないため、バイナリ検索ツリー、バイナリソートツリー、バイナリ検索ツリーとも呼ばれます

  • 完全な二分木:二分木の高さをhとすると、h番目のレイヤーを除いて、他のレイヤーのノード数(1〜h-1)が最大数に達し、h番目のレイヤーに葉ノードがあり、葉ノードはすべて左から右に配置された、これは完全な二分木です。
    完全な二分木:葉ノードを除くすべてのノードには左と右の子葉があり、葉ノードはすべて二分木の下部にあります

  • 2.二分木の特徴

  • 1)ツリーの検索、削除、挿入の時間の複雑さはすべてO(logN)です。

  • 2)二分木をトラバースする方法には、事前順序、中間順序、および事後順序があります。

  • 3)不均衡なツリーとは、ルートの左側と右側にある子ノードの数の不一致を指します

  • 4)空でない二分木では、i番目の層のノードの総数は2 ^(i-1)、i> = 1を超えません

  • 5)深さがhの二分木は最大2 ^(h-1)個のノード(h> = 1)を持ち、少なくともh個のノードを持っています

  • 6)バイナリツリーの場合、そのリーフノードツリーがN0で、次数2のノードの総数がN2の場合、N0 = N2 + 1

9.奇数と偶数の配列を作成し、すべての奇数が左端にあり、偶数がすべて右端にあることを認識するアルゴリズムを記述します。

/**
 * 定义一个方法接受一个int数组,在方法内新建一个数组
 * 将传进来的数组中的元素装进去,但是要求奇数在左,偶数在右
 * 最后返回这个新数组,在main方法中调用定义数组,调用该方法,获取返回值
 * 遍历输出返回的数组
 */
public class  Test{
    
    
    public static int[] newArray(int[] arr){
    
    
        int[] newArr = new int[arr.length];//定义新数组
        //定义两个变量
        int index1=0;
        int index2=arr.length-1;
        for (int i = 0; i < arr.length; i++){
    
    
            if(arr[i]%2!=0){
    
    
                //奇数放到新数组左边
                newArr[index1]=arr[i];
                index1++;
            }else {
    
    
                //偶数放到新数组右边
                newArr[index2]=arr[i];
                index2--;
            }
        }
        return newArr;
    }

    public static void main(String[] args) {
    
    
        int[] arr = {
    
    1,2,3,4,5,6,7,8,9,0};
        int[] newArr = newArray(arr);
        //遍历输出
        for (int i = 0; i < newArr.length; i++) {
    
    
            System.out.println(newArr[i]+"\t");
        }
    }

}

10.javaデータ構造

Javaは主に以下のデータ構造を持っています

  • 1)配列
  • 2)リンクリスト
  • 3)スタックとキュー
  • 4)二分木
  • 5)ヒープとスタック
  • 6)ハッシュテーブル
  • 7)赤黒木

おすすめ

転載: blog.csdn.net/sun_0128/article/details/108571791