C++で配列内の重複要素をすべて検出する方法
整数の配列を考えてみましょう。各要素は 1 ≤ a[i] ≤ n(n は配列のサイズ)の範囲にあり、一部の要素は2回出現し、それ以外の要素は1回だけ出現するとします。このとき、配列内に2回出現するすべての要素を見つける必要があります。たとえば、配列が [4,3,2,7,8,2,3,1] である場合、出力は [2, 3] となります。
アルゴリズムの考え方
この問題は「符号反転マーキング」というテクニックを使うことで、余分なメモリをほとんど使わずに解くことができます。要素の値が必ず 1 以上 n 以下であるという制約を利用し、各値をインデックスとして対応する位置の要素の符号を負にすることで、「その値がすでに出現済みかどうか」を記録します。アクセスした位置がすでに負になっていれば、その値は2回目の出現、つまり重複していることが分かります。
計算量は時間 O(n)、追加の空間計算量は出力を除いて O(1) であり、非常に効率的です。
解法の手順
- n を配列のサイズとし、結果を格納するための配列 ans を作成します。
- i を 0 から n−1 まで繰り返します。
- x に nums[i] の絶対値を代入します。
- x から 1 を引きます(0始まりのインデックスへ変換)。
- nums[x] が負であれば、x + 1 を ans に追加します。そうでなければ nums[x] *= -1 として符号を反転させます。
- 最後に ans を返します。
実装例(C++)
理解を深めるために、以下の実装を見てみましょう。
#include <bits/stdc++.h>
using namespace std;
void print_vector(vector<auto> v){
cout << "[";
for(int i = 0; i<v.size(); i++){
cout << v[i] << ", ";
}
cout << "]"<<endl;
}
class Solution {
public:
vector<int> findDuplicates(vector<int>& nums) {
int n = nums.size();
vector <int> ans;
for(int i = 0; i < n; i++){
int x = abs(nums[i]);
x--;
if(nums[x] < 0) ans.push_back(x + 1);
else nums[x] *= -1;
}
return ans;
}
};
main(){
Solution ob;
vector<int> v = {4,3,2,7,8,2,3,1};
print_vector(ob.findDuplicates(v));
}入力
[4,3,2,7,8,2,3,1]
出力
[2,3]
-
C++で配列内のすべてのペアの和のXORを計算する方法
問題の概要 この問題では、サイズnの配列arr[]が与えられます。私たちのタスクは、配列内のすべてのペアについて要素の和を求め、それらの和のXORを計算するプログラムを作成することです。 例で問題を理解しましょう 入力: arr[] = {5, 7, 9} 出力: 22 説明: (5+5) ^ (5+7) ^ (5+9) ^ (7+5) ^ (7+7) ^ (7+9) ^ (9+5) ^ (9+7) ^ (9+9) = 22 解法1: 単純なアプローチ(ネストしたループ) 最もシンプルな解法は、ネストしたループを使用して配列からすべての可能なペアを生成し、各ペアの和のXORを順に計算していく方
-
【C++】配列内のすべての素数の積を求める方法
整数型配列 arr[] が与えられたとき、その配列に含まれるすべての素数を見つけ出し、それらの積を計算するのが本記事のテーマです。素数とは、1とその数自身でしか割り切れない正の整数のことです。たとえば、2、3、5、7、11などが素数に該当します。それでは、次の配列を例に解を求めてみましょう。入力: arr[] = { 11, 20, 31, 4, 5, 6, 70 }出力: 1705説明: 配列内の素数は 11、31、5 の3つであり、その積は 11 × 31 × 5 = 1705 となります。入力: arr[] = { 1, 2, 3, 4, 5, 6, 7 }出力: 210説明: 配列内の