回転配列の定義: 配列の最初のいくつかの要素を配列の最後に移動します。これを配列の回転と呼びます。
要素値が重複する可能性のある配列番号を指定すると、元は昇順の配列であり、上記のようにローテーションが実行されました。回転した配列の最小要素を返してください。たとえば、配列 [3,4,5,1,2] は [1,2,3,4,5] の回転であり、配列の最小値は 1 です。
- 例 1:
入力: [3,4,5,1,2]
出力: 1- 例 2:
入力: [2,2,2,0,1]
出力: 0
- 問題解決のアイデア
質問の意味によると、最初は総当たりで解決し、変数を使用して現在のトラバーサル プロセス中に検出された最小値を記録し、トラバーサルが完了した後に最小値を返すことができます。
しかし、そのような暴力は優雅ではありません!
配列が回転していることがわかっているため、走査プロセス中に、numbers[0] 未満の数がある限り、その数は最小値でなければならないので、それを味わうことができます。気をつけて。
ほら、それが激しい爆発だとしても、賞賛に値する輝点があるに違いない。
うわさ話はもう十分です。ブルート フォースは私たちの目標ではありません。私たちの目標は、アルゴリズムの複雑さを可能な限り減らすことです。そのため、ここでは二分法を使用します。
最初に、左と右に 2 つのポインターを作成して、それぞれ最初と最後の数字を指すようにし、2 つのポインターの間の中間インデックス値 mid を計算すると、次の 3 つの状況が発生します。
- middle > right : 最小値は middle の右側になければならないという意味なので、 left は middle + 1 の位置に移動します。
- middle < right : 最小値は middle または middle の左側にある必要があるため、right は middle の位置に移動します。
- middle は left ポインターの値よりも大きくも right ポインターの値よりも小さくありません, つまり、 middle は left ポインターの値または right ポインターの値に等しい可能性があります.右ポインタをデクリメントして、最小値を 1 つずつ見つけます。
方法 1: 二分法
/**
* @param {number[]} numbers
* @return {number}
*/
var minArray = function(numbers) {
let left=0;
let right=numbers.length-1;
while(left<right){
var mid=left + Math.floor((right-left)/2);
if(numbers[mid]>numbers[right]){
left=mid+1;
}else if(numbers[mid]<numbers[right]){
right=mid;
}else{
right--;
}
}
return numbers[left];
};
方法 2: ブラスト法
/**
* @param {number[]} numbers
* @return {number}
*/
// 暴破【不推荐】
var minArray = function(numbers) {
for(let i = 0; i < numbers.length; i++){
if(numbers[i] < numbers[0]){
return numbers[i];
}
}
return numbers[0];
}
Jianshu Tongwen のJS ローテーション配列の最小数に注意してください。