0到n-1中缺失的数字
方法一:数学计算,等差数列求和之后减去数组和即可:
O
(
n
)
O(n)
O(n)
class Solution {
public:
int getMissingNumber(vector<int>& nums) {
int n = nums.size() + 1;//输入的是n - 1项,所以要+1,才是原来的n
int sum = (0 + n - 1) *n / 2;
for (auto x : nums) sum -= x;
return sum;
}
};
推荐方法二:具有二段性,因此考虑二分:
O
(
l
o
g
n
)
O(logn)
O(logn)
class Solution {
public:
int getMissingNumber(vector<int>& nums) {
if (nums.empty()) return 0;
int l = 0, r = nums.size() - 1;
while (l < r) {
int mid = l + r >> 1;
if (nums[mid] != mid) r = mid;
else l = mid + 1;
}
if (nums[r] == r) r ++ ;
return r;
}
};
数组中数值和下标相等的元素
依然可以用二分来做。
class Solution {
public:
int getNumberSameAsIndex(vector<int>& nums) {
int l = 0, r = nums.size() - 1;
while (l < r) {
int mid = l + r >> 1;
if (nums[mid] - mid >=0) r = mid;
else l = mid + 1;
}
if (nums[r] - r == 0) return r;
return -1;
}
};
二叉搜索树的第k个结点
按照中序遍历,没遍历一个节点就让k–,这样等k减到0的时候就可以得到答案。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode *ans;
TreeNode* kthNode(TreeNode* root, int k) {
dfs(root, k);
return ans;
}
void dfs(TreeNode* root, int &k) {
if (!root) return;
dfs(root->left, k);
k--;
if (!k) ans = root;
if(k > 0) dfs(root->right, k);
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int treeDepth(TreeNode* root) {
if (!root) return 0;
return max(treeDepth(root->left), treeDepth(root->right)) + 1;
}
};
平衡二叉树
利用上上个题的思路,将求深度的代码稍作修改,不重复求深度。因为只遍历结点一次,所以最坏情形为O(n)。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool res = true;
bool isBalanced(TreeNode* root) {
dfs(root);
return res;
}
int dfs(TreeNode *root) {
if (!root) return 0;
int left = dfs(root->left), right = dfs(root->right);
if (abs(left - right) > 1) res = false;
return max(left, right) + 1;
}
};
两个相同的数,异或的结果为0;
- 异或得到 x^y
- 取 x与y中第k位为1的数
- 将数分为两个集合,第k位为1的集合和第k位不是1的集合
- 其中x y分别在这两个集合,且相同的元素是在同一个集合里面
- 于是将其转化成了求重复数字中的单个数值的问题
class Solution {
public:
vector<int> findNumsAppearOnce(vector<int>& nums) {
int sum = 0;// x^y
for (auto x : nums) sum ^= x;
//从sum里找到任意一位二进制表示不为0的
int k = 0;
while (!(sum >> k & 1)) k++;
int first = 0;
for (auto x : nums)
if (x >> k & 1)
first ^=x;
return vector<int> {first, sum ^ first};
}
};
class Solution {
public:
int findNumberAppearingOnce(vector<int>& nums) {
if(nums.size() ==0)return -1;
int bitSum[32]= {0};
for(int i = 0; i < nums.size();i++){
int bitMask = 1;
for(int j = 31; j >=0; j--){
int bit = nums[i] & bitMask;
if(bit != 0)
bitSum[j] += 1;
bitMask = bitMask <<1;
}
}
int res = 0;
for(int i = 0; i < 32; ++i){
res = res << 1;
res += bitSum[i] % 3;//
}
return res;
}
};
方法二:
class Solution {
public:
int findNumberAppearingOnce(vector<int>& nums) {
int ones = 0, twos = 0;
for (auto x : nums) {
ones = (ones ^ x) & ~twos;
twos = (twos ^ x) & ~ones;
}
return ones;
}
};
和为S的两个数字
极其经典的题,因为是leetcode第一题2333333
暴力做法,两重循环:
O
(
n
2
)
O(n^2)
O(n2)
class Solution {
public:
vector<int> findNumbersWithSum(vector<int>& nums, int target) {
for (int i = 0; i < nums.size(); i++)
for(int j = 0; j < i; j++)
if(nums[i] + nums[j] == target)
return vector<int>{nums[i], nums[j]};
}
};
显然这是不够的,我们需要更好的做法:其实这种题最容易想到的做法也就是哈希表了! O ( n ) O(n) O(n)
class Solution {
public:
vector<int> findNumbersWithSum(vector<int>& nums, int target) {
unordered_set<int> hash;
for (auto x : nums) {
if (hash.count(target - x)) return vector<int> ({target - x, x});
hash.insert(x);
}
return vector<int> ();
}
};
class Solution {
public:
vector<vector<int> > findContinuousSequence(int sum) {
vector<vector<int>> res;
for (int i = 1, j = 1, s = 1; i <= sum; i++) {
while (s < sum) j++, s +=j;
if (s == sum && j > i) {
vector<int> line;
for (int k = i; k <= j; k++) line.push_back(k);
res.push_back(line);
}
s -= i;
}
return res;
}
};
class Solution {
public:
string reverseWords(string s) {
reverse(s.begin(), s.end());//整体翻转
//将内部的每个单词翻转
for (int i = 0; i < s.size(); i++) {
int j = i;
while (j < s.size() && s[j] != ' ') j++;//非常经典的找一段连续空间的代码模板
reverse(s.begin() + i, s.begin() + j);//翻转
i = j;//此时j指向空格,等下一个循环++。正好指向下一个单词的首字母
}
return s;
}
};
提供一个空格处理的方法:
class Solution {
public:
string reverseWords(string s) {
int start = 0;
for (int i = 0; i < s.size(); i++) {
if (s[i] == ' ') continue;
int j = i, t = start;
while (j < s.size() && s[j] != ' ') s[t++] = s[j++];
reverse(s.begin() + start, s.begin() + t);
s[t++] = ' ';
start = t, i = j;
}
if (start) start--;
s.erase(s.begin() + start, s.end());
reverse(s.begin(),s.end());
return s;
}
};
- 整个数组翻转
- 左半边翻转
- 右半边翻转
class Solution {
public:
string leftRotateString(string str, int n) {
reverse(str.begin(), str.end());
reverse(str.begin(), str.begin() + str.size() - n);
reverse(str.begin() + str.size() - n, str.end());
return str;
}
};