Interview_C++_day27
通过位运算实现加减乘除取模
- 加法操作
对于每一位而言,在不考虑进位的情况下,可以得到
\[ 0+0 = 0\\
0+1 = 1\\
1+0 = 1\\
1+1 = 0
\]
显然,上面的情况符合 异或 操作且只有第四种情况发生了进位,进位情况符合 与 操作。在所有发生进位处,应该在更高的一位处加一,这个值可以通过 左移 操作实现。那么就可以得到
\[ x+y = x \oplus y + (x \& y)<<1
\]
可以发现,后面的式子变成了一个新的加法式,那么只要递归计算即可。当 \((x \& y)<<1 == 0\) 时,就消除了加法式。
ll add(ll x, ll y) {
ll newx = x^y;
ll newy = (x&y)<<1;
if(newy == 0) return newx;
return add(newx, newy);
}
- 减法操作
减法操作可以看成
\[\begin{aligned}
-y &= \sim y+1\\
x+y & = x+(-y)\\
& = x + \sim y+1
\end{aligned}
\]
同样可以通过加法式得到
ll sub(ll x, ll y) {
return add(x, add(~y, 1));
}
- 乘法操作
假设 \(y=1010\),则可以关注于二进制上的 \(1\) 位,那么可以将 \(x*y\) 做出拆解
\[\begin{aligned}
x*y &= x*1010\\
&= x*1000 + x*0010
\end{aligned}
\]
而这个当乘数只有一个 \(1\) 时,可以通过二进制的左移操作实现。
ll mul(ll x, ll y) {
ll ans = 0;
int flag = x^y;
x = x<0 ? add(~x, 1) : x;
y = y<0 ? add(~y, 1) : y;
for(int i=0; (1ll<<i)<=y; i++) {
if(y&(1ll<<i)) {
ans = add(ans, x<<i);
}
}
return flag<0 ? add(~ans, 1) : ans;
}
- 除法操作
和乘法操作思想一样,枚举答案每一位是否为 \(1\),通过左移来得到乘积并减去。先从大的开始找,如果有一位是 \(1\),那么就在答案将这一位设成 \(1\)。
ll divide(ll x, ll y) {
ll ans = 0;
int flag = x^y;
x = x<0 ? add(~x, 1) : x;
y = y<0 ? add(~y, 1) : y;
for(int i=31; i>=0; i--) {
if(x >= (1ll*y<<i)) {
ans |= (1ll<<i);
x = sub(x, 1ll*y<<i);
}
}
return flag<0 ? add(~ans, 1) : ans;
}
- 取模操作
已经得到了除法的结果,那么取模操作也很容易实现了
ll mod(ll x, ll y) {
x = x<0 ? add(~x, 1) : x;
y = y<0 ? add(~y, 1) : y;
return sub(x, mul(y, divide(x, y)));
}
为什么子类对象可以赋值给父类对象而反过来却不行
- 子类继承于父类,它含有父类的部分,又做了扩充。如果子类对象赋值给父类变量,则使用该变量只能访问子类的父类部分。
- 如果反过来,这个子类变量如果去访问它的扩充成员变量,就会访问不到,造成内存越界。
为什么 \(free\) 时不需要传指针大小
\(free\) 要做的事是归还 \(malloc\) 申请的内存空间,而在 \(malloc\) 的时候已经记录了申请空间的大小,所以不需要传大小,直接传指针就可以。
手写链表实现 \(LRU\)
class LRU {
private:
struct Node {
int val;
Node *pre, *suf;
Node() {
pre = suf = nullptr;
}
Node(int _val) {
val = _val;
pre = suf = nullptr;
}
};
int size;
int capacity;
Node *head;
unordered_map<int, Node*> mp;
Node* find(int val) {
if(mp.count(val)) {
return mp[val];
} else {
return nullptr;
}
}
void del(Node *node) {
if(node == nullptr) return ;
node->pre->suf = node->suf;
node->suf->pre = node->pre;
mp.erase(node->val);
if(node == head) head = head->suf;
size--;
}
void add(Node *node) {
if(head == nullptr) {
head = node;
head->suf = head;
head->pre = head;
mp[node->val] = node;
} else {
node->suf = head;
node->pre = head->pre;
head->pre = node;
node->pre->suf = node;
mp[node->val] = node;
head = node;
}
size++;
}
public:
LRU() {
mp.clear();
head = nullptr;
size = capacity = 0;
}
void reverse(int _capacity) {
capacity = _capacity;
}
void insert(int val) {
Node *node = new Node(val);
Node *selectnode = find(val);
del(selectnode);
if(size == capacity) {
del(head->pre);
}
add(node);
}
void view() {
Node *p = head;
do {
cout << p->val << " ";
p = p->suf;
} while(p != head);
cout << endl;
}
}lru;