136:只出現一次的數
題目:
給定一個非空整數數組,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
求解方法:
- map平衡二叉樹。統計每個元素出現的次數,返回次數爲1的元素即可。時間複雜度爲,空間複雜度爲.
- unordered_map散列表。統計每個元素出現的次數,返回次數爲1的元素即可。時間複雜度爲,空間複雜度爲.
- 異或位運算。將數組中所有元素進行異或運算,返回最後異或的結果即可。時間複雜度爲,空間複雜度爲.
注意事項:
- 利用異或的原因:
代碼:
class Solution {
public:
int singleNumber(vector<int>& nums) {
return singleNumberWayIII(nums);
}
// way1:map統計;時間複雜度爲o(nlogn),空間複雜度爲o(n).
int singleNumberWayI(vector<int>& nums) {
int n = nums.size();
if(n == 0){
return -1;
}
// count by map
map<int,int> m;
for(int num:nums){
m[num]++;
}
int res = -1;
// return when count = 1
for(map<int,int>::iterator it = m.begin();it != m.end(); it++){
if(it->second == 1){//important:不是*it->second而是it->second
res = it->first;
break;
}
}
return res;
}
// way2:unordered_map;時間複雜度爲o(nlogn),空間複雜度爲o(n).
int singleNumberWayII(vector<int>& nums) {
int n = nums.size();
if(n == 0){
return -1;
}
// count by unordered_map
unordered_map<int,int> m;
for(int num:nums){
m[num]++;
}
// return when count = 1
int res = -1;
for(unordered_map<int,int>::iterator it = m.begin(); it != m.end(); it++){
if(it->second == 1){//important:不是*it->second而是it->second
res = it->first;
break;
}
}
return res;
}
// way3:異或位運算;時間複雜度爲o(n),空間複雜度爲
int singleNumberWayIII(vector<int>& nums) {
int n = nums.size();
if(n == 0){
return -1;
}
int res = 0;
for(int num:nums){
res ^= num;
}
return res;
}
};
137:只出現一次的數II
題目:
給定一個非空整數數組,除了某個元素只出現一次以外,其餘每個元素均出現了三次。找出那個只出現了一次的元素。
求解方法:
- map平衡二叉樹。統計每個元素出現的次數,返回次數爲1的元素即可。時間複雜度爲,空間複雜度爲.
- unordered_map散列表。統計每個元素出現的次數,返回次數爲1的元素即可。時間複雜度爲,空間複雜度爲.
- 數組去重後數據和的3倍與原數組和的差除以2。時間複雜度爲,空間複雜度爲。原因是假設數組共個數,其和記作,去重剩餘個數,其和記作.去重後數組和的三倍即是個數的和,減去個數的和,剩餘的就是隻出現一次的數的兩倍。即:
- 三進制不進位加法。上一題中利用異或運算,異或也稱作二進制不進位加法,此題只要利用三進制不進位加法即可。時間複雜度爲,空間複雜度爲.
注意事項:
- 第三種利用數組和的方法,在求和的時候和藥用long類型的數據,否則會越界.
- set和map<int,int>以及unordered_map<int,int>的迭代器的使用的不同方法。
代碼:
class Solution {
public:
int singleNumber(vector<int>& nums) {
return singleNumberWayIV(nums);
}
// way1:map統計;時間複雜度爲o(nlogn),空間複雜度爲o(n).
int singleNumberWayI(vector<int>& nums) {
int n = nums.size();
if(n == 0){
return -1;
}
// count by map
map<int,int> m;
for(int num:nums){
m[num]++;
}
int res = -1;
// return when count = 1
for(map<int,int>::iterator it = m.begin();it != m.end(); it++){
if(it->second == 1){//important:不是*it->second而是it->second
res = it->first;
break;
}
}
return res;
}
// way2:unordered_map;時間複雜度爲o(nlogn),空間複雜度爲o(n).
int singleNumberWayII(vector<int>& nums) {
int n = nums.size();
if(n == 0){
return -1;
}
// count by unordered_map
unordered_map<int,int> m;
for(int num:nums){
m[num]++;
}
// return when count = 1
int res = -1;
for(unordered_map<int,int>::iterator it = m.begin(); it != m.end(); it++){
if(it->second == 1){//important:不是*it->second而是it->second
res = it->first;
break;
}
}
return res;
}
// way3:sum of array of no duplication and sum of array;時間複雜度爲o(nlogn),空間複雜度爲o(n).
int singleNumberWayIII(vector<int>& nums) {
int n = nums.size();
if(n == 0){
return -1;
}
// get sum of array and remove the duplications meanwhile
set<int> s;
long sum1 = 0;//important:long類型
for(int num:nums){
sum1 += num;
s.insert(num);
}
// get sum of no duplications
long sum2 = 0;
for(set<int>::iterator it = s.begin(); it != s.end(); it++){
sum2 += (*it);//important:是*it不是it
}
return (3*sum2 - sum1)/2;
}
// way4:三進制不進位加法;時間複雜度爲o(n),空間複雜度爲o(1).
/*(1)用 one 記錄到當前處理的元素爲止,二進制1出現“1次”(mod 3 之後的 1)的有哪些二進制位;
(2)用 two 記錄到當前計算的變量爲止,二進制1出現“2次”(mod 3 之後的 2)的有哪些二進制位。
(3)當 one 和 two 中的 某一位 同時爲1時表示該二進制位上1出現了3次,此時需要清零。即用二進制模擬三
進制運算。
(4)最終 one 記錄的是最終結果。
*/
int singleNumberWayIV(vector<int>& nums) {
int one = 0,two = 0, three = 0;
for(int num:nums){
one = one ^ num & ~two;
two = two ^ num & ~one;
}
return one;//important:返回的是one(因爲需要返回的是出現一次的數)
}
};
260:只出現一次的數III
題目:
給定一個整數數組 nums,其中恰好有兩個元素只出現一次,其餘所有元素均出現兩次。 找出只出現一次的那兩個元素。
求解方法:
- 排序。(1)判斷第一個元素和最後一個元素;(2)判斷中間元素,只出現一次的元素的特點是既不等於前面的數也不等於後面的數。時間複雜度爲,空間複雜度爲.
- unordered_map散列表。統計每個元素出現的次數,返回次數爲1的元素即可。時間複雜度爲,空間複雜度爲.
- 位運算1。(1)通過異或運算找到只出現一次的兩個元素的異或值記作mask = a^b,a和b因爲不同,所以a和b的二進制中至少存在一位不同,即mask中至少存在一個1;(2)通過mask = mask & (-mask)找到mask中最右邊的1;(3)通過mask對這兩個數分組,找到兩個數並更新結果。時間複雜度爲,空間複雜度爲。
- 位運算2。(1)通過異或運算找到只出現一次的兩個元素的異或值記作mask = a^b,a和b因爲不同,所以a和b的二進制中至少存在一位不同,即mask中至少存在一個1;(2)通過mask = mask & (~mask+1)找到mask中最右邊的1;(3)通過mask對這兩個數分組,找到兩個數並更新結果。。時間複雜度爲,空間複雜度爲.
注意事項:
代碼:
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
return singleNumberWayIV(nums);
}
//way1:sort+check;時間複雜度爲o(nlogn),空間複雜度爲o(1);
/*
(1)判斷第一個元素和最後一個元素;
(2)判斷中間元素,只出現一次的元素的特點是既不等於前面的數也不等於後面的數。
*/
vector<int> singleNumberWayI(vector<int>& nums) {
int n = nums.size();
vector<int> res;
if(n == 0){
return res;
}
//sort
sort(nums.begin(),nums.end());
// check the first number
if(nums[0] != nums[1]){
res.push_back(nums[0]);
}
// check the last number
if(nums[n-1] != nums[n-2]){
res.push_back(nums[n-1]);
}
// check the middle element
for(int i=1; i<n-1;i++){
if(nums[i]!=nums[i-1] && nums[i]!=nums[i+1]){
res.push_back(nums[i]);
}
}
return res;
}
// way2:unordered_map;時間複雜度爲o(nlogn),空間複雜度爲o(n).
vector<int> singleNumberWayII(vector<int>& nums) {
int n = nums.size();
vector<int> res;
if(n == 0){
return res;
}
// count
unordered_map<int,int> m;
for(int num:nums){
m[num]++;
}
// push to the res when count = 1
for(unordered_map<int,int>::iterator it = m.begin(); it != m.end(); it++){
if(it->second == 1){
res.push_back(it->first);
}
}
return res;
}
// way3:位運算;use n = n & (-n) to find the first 1 from right;時間複雜度爲o(n),空間複雜度爲o(1).
vector<int> singleNumberWayIII(vector<int>& nums) {
int n = nums.size();
vector<int> res(2,0);
if(n == 0){
return res;
}
// 異或
int mask = 0;
for(int num:nums){
mask ^= num;
}
// find first 1 from right
mask = mask & (-mask);
// find the result
for(int num:nums){
if((mask & num) == mask){
res[0] = res[0] ^ num;
}else{
res[1] = res[1] ^ num;
}
}
return res;
}
// way4:位運算;use n = n & (~n+1) to find the first 1 from right;時間複雜度爲o(n),空間複雜度爲o(1).
vector<int> singleNumberWayIV(vector<int>& nums) {
int n = nums.size();
vector<int> res(2,0);
if(n == 0){
return res;
}
// 異或
int mask = 0;
for(int num:nums){
mask ^= num;
}
// find first 1 from right
mask = mask & (~mask+1);
// find the result
for(int num:nums){
if((mask & num) == mask){
res[0] = res[0] ^ num;
}else{
res[1] = res[1] ^ num;
}
}
return res;
}
};