位运算实现加法
- 不能 INT_MIN进行左移, INT_MAX左移一位溢出, 输出-2;
class Solution {
public:
// 之前学的计算机中负数是以补码的形式参与运算, 与这里并不矛盾
// 这些位运算中, 负数参与的时候已经转换成了补码, 2^1 = 3, -2^1 = -1 (如果是原码, 应该是-3)
// 位运算的时候, 符号位也参与了运算
int add(int a, int b) {
int x = INT_MAX; // 0111, 对正数无影响, 对负数最高位改变
while(b != 0) //进位为0的时候跳出
{
int c = (a & b) << 1; // (INT_MIN << 会报错, , 进位操作可以始终把最高位弄成0), 需要将最高位符号位变为0
a = a ^ b; // a作为本位求和, ^保证了最高位的符号位不变 // 先假设没有进位计算一波, 然后判断进位b是不是0, 不是的话, 再来一次
b = c; // 始终把b作为进位
}
return a;
}
};
输出大数
- 输出0-n为最大数, 之间所有数.
- 无论是int, long, long long 都会有上限,大数只能通过字符串输出
- 首字母不能是0, 并且从1开始, 就用了下面那个判断
- 递归如果最后结果只有一个, 就带返回值
- 如果最后结果很多个, 就不带返回值, 使用一个vector, 每次在结束递归的时候装入.
void dfs(int th, int n, string& res, vector<string>& v)
{
if (th == n + 1)
{
v.push_back(res);
return ;
}
for(int i = 0; i <= 9; i++)
{
string c = to_string(i);
/*
if (th == 1 && i == 0)
c = ""; // 只去除首字母是0, 不去除单独0
*/
res += c;
if(res == "0") //去除首字母是0 和 单独一个0
res = "";
dfs(th+1, n, res, v);
res = res.substr(0, res.size()-1);
}
}
void test02()
{
int n;
cin>>n;
string s = "";
vector<string> v;
dfs(1, n, s, v);
for(auto& i:v)
cout<<i<<endl;
}
和为s的连续正数序列
- 滑动窗口
- 求和不需要每次都遍历, ±一头一尾即可
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
int l = 1, r = 2;
int sum = 3;
vector<vector<int>> res;
vector<int> temp;
while(true)
{
if(sum < target)
{
sum += (++r);
}
else if (sum == target)
{
for(int i = l; i <= r; i++)
temp.push_back(i);
res.push_back(temp);
temp.clear();
sum -= (l++);
}
else
{
if (r - l == 1)
break;
sum -= (l++);
}
}
return res;
}
};
判断二进制数中1的个数
- C++的主要数据类型只有三种:
bool``整型
(char 是长度为1字节的整型, 用来存放ASCII)浮点型
*_t是typedef定义的标识
, 我们所看到的 uint8_t、uint16_t、uint32_t都不是新的数据类型
,而是通过typedef给类型起得别名。- size_t 也是无符号整型, 一种用来记录大小的数据类型. sizeof的返回值, 容器的大小v.size()
通常是size_t类型. (32位 4字节, 64位 8字节)
/* There is some amount of overlap with <sys/types.h> as known by inet code */
#ifndef __int8_t_defined
# define __int8_t_defined
typedef signed char int8_t;
typedef short int int16_t;
typedef int int32_t;
# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif
#endif
/* Unsigned. */
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
#ifndef __uint32_t_defined
typedef unsigned int uint32_t;
# define __uint32_t_defined
#endif
#if __WORDSIZE == 64
typedef unsigned long int uint64_t;
#else
__extension__
typedef unsigned long long int uint64_t;
#endif
注意,uint8_t实际上就是一个char,所以输出 uint8_t类型的变量实际上输出对应的字符,而不是数值,比如:
uint8_t num=67;
cout << num << endl; //输出结果为C
- for循环比while循环更快?
- n&(n-1) 每次可以消除最右边的一个1 (
图片来源, 力扣Krahets的回答
)
- 右移和左移相当于除以2和乘2, 因此是
O(log2n)
的时间复杂度, 只是这里O(log2n) <= 32
class Solution {
public:
int hammingWeight(uint32_t n) {
int count = 0;
/*
while(n)
{
count += (n&1); // O(log2n)的时间复杂度
n = n>>1;
}*/
for(int i = 0; i < 32; i++)
{
count += ((n & (1<<i)) == 0)?0:1;
}
/*
while(n)
{
count++;
n &= (n-1); // O(M)时间复杂度, M为1的个数
}*/
return count;
}
};
BST的最近公共结点
- 时间复杂度要考虑最坏情况, 因为树的最差情况是链表, 因此时间复杂度是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:
/*
// 所有tree的通用解法, 不一定是BST
// 自底向上, p,q沿着路径向上, 汇合的时候, 就把汇合结点一直向上
TreeNode* dfs(TreeNode* root, TreeNode* p, TreeNode* q)
{
if (root == p || root == q) return root;
if (root == NULL) return NULL;
TreeNode* left = dfs(root->left, p, q);
TreeNode* right = dfs(root->right, p, q);
if (left && right) return root;
else if (!left && right) return right;
else if (left && !right) return left;
else
return NULL;
}
*/
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
// 如果p,q在root的左右子树中, 那么root就是最近共同祖先结点
// 否则在哪边的子树, 就继续遍历哪边的子树
// 因为这一题是BST, 因此可以根据结点大小判断
while(root)
{
if(p->val > root->val && q->val > root->val)
root = root->right;
else if (p->val < root->val && q->val < root->val)
root = root->left;
else
break;
}
/* 递归
if(p->val > root->val && q->val > root->val)
return lowestCommonAncestor(root->right, p, q);
else if(p->val < root->val && q->val < root->val)
return lowestCommonAncestor(root->left, p, q);
return root;
*/
return root;
}
};