1. 順序付けされた配列に要素を追加する
まず、挿入する要素の位置を見つけ、次の要素を含む位置を 1 ビット前に戻してから、その要素を配列に挿入します。まず、現在の配列が要素を追加し続けることができるかどうかを判断する必要があります。
/**
* 插入指定位置元素
*
* @param arr 有序数组
* @param size 已经存储的元素数量,从1开始
* @param element 插入的元素
* @return
*/
public static int addByElement(int[] arr, int size, int element) {
// size从1开始表示实际个数,arr.length也是从1开始
if (size >= arr.length) {
return -1;
}
// 防止插入的数大于当前最大值
int index = size;
for (int i = 0; i < size; i++) {
if (element < arr[i]) {
index = i;
break;
}
}
// j开始元素都后移
for (int j = size; j > index; j--) {
arr[j] = arr[j - 1];
}
// 插入元素
arr[index] = element;
return index;
}
2. 指定したposition要素を削除する
まず削除した要素が存在する位置を探し、存在する場合はそれを記録し、その位置の添え字が-1であるかどうかを判断し、-1でない場合は存在することを意味し、すべての要素を移動します削除された要素の後ろから前へ。
/**
* 删除元素key
*
* @param arr 数组
* @param size 数组元素个数从1开始
* @param key 删除元素
* @return
*/
public static int removeByElement(int[] arr, int size, int key) {
if (size >= arr.length) {
return -1;
}
// index是-1,表示不存在
int index = -1;
for (int i = 0; i < size; i++) {
if (arr[i] == key) {
index = key;
break;
}
}
if (index != -1) {
for (int i = index + 1; i < size; i++) {
arr[i - 1] = arr[i];
size--;
}
}
return size;
}
3. 単調系列
単調配列
単調増加または単調減少する配列は単調です。
すべての i <= j について nums[i] <= nums[j] の場合、配列 nums は単調増加します。すべての i <= j に対して nums[i] >= nums[j] である場合、配列 nums は単調減少します。
指定された配列 nums が単調な場合は true を返し、それ以外の場合は false を返します。
3.1 分析
トピックにはインクリメントとデクリメントが含まれているため、直接判断してインクリメントかデクリメントかを知ることはできないため、2 つの変数 inc と desc を使用して記録する必要があります。要素がすべてインクリメントである場合、最終的な inc| の使用は|desc は true のみになります。fasle が表示されると、単調ではなくなります。
public boolean isMonotonic(int[] nums) {
// 递增标志
boolean inc = true;
// 递减标志
boolean desc = true;
for(int i=0;i<nums.length-1;i++){
if(nums[i]>nums[i+1]){
// 由于是递减的,所以递增的不满足,设置为false
inc = false;
}
// 同理
if(nums[i] < nums[i+1]){
desc = false;
}
}
// 只要一个为true就是true,如果都是false那么就不是递增的
return inc || desc;
}
4.挿入位置の検索
挿入位置の検索 ソート
された配列とターゲット値を指定して、配列内でターゲット値を検索し、そのインデックスを返します。配列内に対象の値が存在しない場合は、順番に挿入される位置を返します。
時間計算量が O(log n) のアルゴリズムを使用してください。
4.1 分析
logn の時間計算量が必要なテーマですが、最初に考えたのは 2 点です。
public int searchInsert(int[] nums, int target) {
int n = nums.length;
int left =0;
int right = n-1;
int ans = n;
while(left<=right){
// 这里要加上相应的括号,否则优先级会报错
int mid = ((right-left) >>1) +left;
if(target<=nums[mid]){
ans = mid;
right = mid-1;
}else{
left = mid+1;
}
}
return ans;
}
5. ソートされた 2 つの配列をマージする
2 つのソートされた配列のマージ
2 つの整数配列 nums1 と nums2 が降順ではなく、それぞれ nums1 と nums2 の要素の数を示す 2 つの整数 m と n が与えられているとします。
結合された配列も降順に配置されるように、nums2 を nums1 に結合してください。
注: 最終的に、マージされた配列は関数によって返されるのではなく、配列 nums1 に格納される必要があります。この状況に対処するために、nums1 の初期長は m + n です。ここで、最初の m 要素はマージする必要がある要素を表し、最後の n 要素は 0 であるため無視する必要があります。nums2 の長さは n です。
5.1 分析
5.1.1 まずすべての要素を nums1 に追加し、次に nums1 をソートします。
public void merge(int[] nums1, int m, int[] nums2, int n) {
for(int i=0;i<nums2.length;i++){
nums1[m+i] = nums2[i];
}
Arrays.sort(nums1);
}
しかし、明らかに効率は高くありません。最初に nums2 を走査したときの時間計算量は O(n)、2 回目は Arrays のソートを使用し、最下層はクイック ソートで、時間計算量は O(nlogn) でした。
5.2.2 2 つの配列は順序どおりであるため、2 つの配列の最後の要素を比較し、大きい方の要素を nums1 の最後に置き、最後に未完成の要素を nums1 に入れるだけで済みます。
public static void merge(int[] nums1, int m, int[] nums2, int n) {
// 合并索引位置
int i = m + n - 1;
// nums1的最后一个元素
int len1 = m - 1;
// nums2的最后一个元素
int len2 = n - 1;
while (len1 >= 0 && len2 >= 0) {
if (nums1[len1] <= nums2[len2]) {
// 将最大的元素放入nums1的末尾
nums1[i--] = nums2[len2--];
} else {
nums1[i--] = nums1[len1--];
}
}
// 判断剩余数组是否有空余元素
while (len2 != -1) nums1[i--] = nums2[len2--];
while (len1 != -1) nums1[i--] = nums1[len1--];
}
ここでの時間計算量は、O(m+n) の 2 つの配列の長さです。効率が依然として非常に高いことがわかりますが、
要約する
配列問題の難しさは、問題を解決する比較的合理的な方法を選択する方法にあり、特に配列内の要素の追加と要素の削除の移動には特別な注意が必要です。