記事のディレクトリ
-
- 質問ガイド
- 総括する(***)
- ハッシュテーブルの一般的な方法:出現回数を数える
- [242.有効な文字失読症](https://leetcode-cn.com/problems/valid-anagram/)
- [349. 2つの配列の共通部分](https://leetcode-cn.com/problems/intersection-of-two-arrays/)
- [202.ハッピー数](https://leetcode-cn.com/problems/happy-number/)
- [1. 2つの数値の合計](https://leetcode-cn.com/problems/two-sum/)
- [454. 4つの数字の加算II](https://leetcode-cn.com/problems/4sum-ii/)
- [383.身代金メモ](https://leetcode-cn.com/problems/ransom-note/)
- [15. 3つの数値の合計(ソート+ダブルポインター)](https://leetcode-cn.com/problems/3sum/)
- [18. 4つの数値の合計(ソート+ダブルポインター、同じ3つの数値の合計)](https://leetcode-cn.com/problems/4sum/)
質問ガイド
総括する(***)
1.ループの時間計算量を減らします:ソート+ダブルポインター、ハッシュテーブル
2. a [i] + a [j] == 0のように複数の変数がある場合、jを修正できます。つまり、0を見つけます。 〜j-1に-a [j]の数があるかどうかは、
3を計算しながら計算できます。ハッシュテーブル:出現回数を数えます!
4.ダブルポインター:単調性が満たされる場合、ダブルポインターを考慮することができます
ハッシュテーブルの一般的な方法:出現回数を数える
ハッシュは時間と引き換えにスペースも犠牲にします
242.有効な文字エイリアンの言葉
分析:
ハッシュテーブルを使用して、各文字が表示される回数と時間計算量をカウントしますO(n)
。私が初めてそれをしたとき、それは直接ソートされました、それは時間の複雑さO(nlogn)
でした。
もちろん、この質問のマッピング範囲は比較的狭く、配列をハッシュテーブルとして使用できます。高度な問題の範囲が広い場合は、配列を使用しないでください。
「そして、ハッシュ値が比較的小さく、特に分散していて、スパンが非常に大きい場合、配列を使用すると、スペースが大幅に浪費されます。」
class Solution {
public:
bool isAnagram(string s, string t) {
// 时间复杂度O(n)
// 空间复杂度O(26)
if(s.size() != t.size()) return false;
unordered_map<char,int> cnt; // 哈希表
for(auto c : s) cnt[c] ++;
for(auto c : t){
cnt[c] -- ;
}
for(auto x : cnt){
if(x.second != 0) return false;
}
return true;
}
};
349.2つのアレイの交差
解決策1:使用するunordered_set
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
// 时间复杂度O(n)
unordered_set<int> num, res;
for(auto c : nums1) num.insert(c); // 把nums1的元素插到unordered_set中
for(auto c : nums2)
if(num.count(c)) res.insert(c);
vector<int> ans(res.begin(), res.end()); // 赋值
return ans;
}
};
解決策2:使用するunordered_map
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
// 哈希表
unordered_map<int,int> hash;
for(auto c : nums1) hash[c] ++ ;
vector<int> res;
for(auto c : nums2)
{
if(hash[c] > 0 ) res.push_back(c), hash[c] = 0 ;
}
return res;
}
};
202.ハッピー数
分析:
タイトルには「無限ループ」と書かれていますsum会重复出现
。これは、「合計の過程で、これは問題を解決するために非常に重要です」という意味です。
class Solution {
public:
bool isHappy(int n) {
unordered_map<int,int> cnt;
while(n != 1)
{
cnt[n] ++;
dfs(n); // 引用改变n的值
if(cnt[n] > 1) return false; // 只要出现次数大于1,说明循环了
}
return true;
}
void dfs(int &n)
{
int res = 0;
while(n > 0){
int t = n % 10;
res += t * t;
n /= 10;
}
n = res;
}
};
1.2つの数値の合計
分析:
1回限りの統計はあまり良くありません、探している間に挿入する方が良いです
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> hash;
// 边求边插入
for(int i = 0;i < nums.size();i ++ ){
if(hash.count(target - nums[i])) return {
hash[target - nums[i]], i};
hash[nums[i]] = i;
}
return {
-1, -1};
}
};
454.4つの数の加算II
分析:最大2つのアレイをループできることが
観察されN = 500
ています。一般的な取り扱い方法!
class Solution {
public:
int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
unordered_map<int,int> hash; // 统计 a + b的值出现的次数
for(int i = 0;i < A.size();i ++ )
for(int j = 0;j < B.size();j ++)
hash[A[i] + B[j]] ++;
int res = 0;
for(int i = 0;i < C.size();i ++ )
for(int j = 0;j < D.size();j ++)
{
int s = C[i] + D[j];
if(hash.count(0 - s)) res += hash[0 - s]; // 这里的处理类似 两数之和
}
return res;
}
};
383.身代金の手紙
class Solution {
public:
bool canConstruct(string r, string m) {
// 哈希计数
unordered_map<char,int> cnt;
for(auto c : m) cnt[c] ++;
for(auto c : r){
cnt[c] -- ;
if(cnt[c] < 0) return false; // 字符不够了
}
return true;
}
};
15. 3つの数値の合計(ソート+ダブルポインター)
分析:並べ替え+ダブルポインター
ハッシュテーブルは重複排除する必要があり、書き込むのが難しすぎます。代わりに並べ替え+ダブルポインターを使用してください。イベントの複雑さはO(n ^ 2)
で、a [i] + a [l] + a [rを見つけることができます。 ] == 0の場合、a [i]を列挙できます。前の並べ替えのため、単調性を満たす必要があります。iが移動すると、lとrが単調に移動するため、ダブルポインタを使用できます。
去重的常用操作
:この質問の難しさは、重複を取り除くことでもあります!
while(l < r && nums[l] == nums[l - 1]) l ++ ;
while(l < r && nums[r] == nums[r + 1]) r -- ;
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
int n = nums.size();
if(n < 3) return res;
sort(nums.begin(), nums.end());
// a[i] + a[l] + a[r] == 0 , 固定a[i]
for(int i = 0;i < n;i ++ )
{
if(nums[i] > 0) return res; // 直接返回了
if(i != 0 && nums[i] == nums[i - 1]) continue; // 去重!关键!
int l = i + 1, r = n - 1;
while(l < r)
{
if(nums[l] + nums[i] + nums[r] == 0) {
res.push_back({
nums[i], nums[l], nums[r]});
l ++ , r -- ;
// 去重的常见操作
while(l < r && nums[l] == nums[l - 1]) l ++ ;
while(l < r && nums[r] == nums[r + 1]) r -- ;
}else if(nums[l] + nums[i] + nums[r] < 0){
l ++ ;
}else{
r -- ;
}
}
}
return res;
}
};
18. 4つの数値の合計(ソート+ダブルポインター、3つの数値の合計と同じ)
分析:時間計算量O(n 3 n ^ {3}n3)、重複排除処理で4つの数字IIを追加するよりも面倒です!
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
int n = nums.size();
sort(nums.begin(), nums.end());
for(int i = 0;i < n ; i++ )
for(int j = i + 1;j < n ;j ++ )
{
// 去重
if(i != 0 && nums[i] == nums[i - 1]) break;
if(j != i + 1 && nums[j] == nums[j - 1]) continue; // 这里是continue
int l = j + 1,r = n - 1;
while(l < r)
{
if(nums[i] + nums[j] + nums[l] + nums[r] == target){
res.push_back({
nums[i], nums[j], nums[l], nums[r]});
l ++ ,r -- ;
while(l < r && nums[l] == nums[l - 1]) l ++ ;
while(l < r && nums[r] == nums[r + 1]) r --;
}else if(nums[i] + nums[j] + nums[l] + nums[r] < target) l ++ ;
else r -- ;
}
}
return res;
}
};