面试题46:求1+2+3+....+n
求1+2+3+....+n,要求不能使用乘除法,不能用for,while,if,else,switch,case等关键字及条件判断语句。
leetcode链接 https://leetcode-cn.com/problems/qiu-12n-lcof/class Solution { // 利用&&运算法左子式为false不进行右子式计算的性质 public: int sumNums(int n) { n && (n += sumNums(n - 1)); return n; } };
解题思路:由判断条件,本题无法使用递归和循环。
网上看到一神人代码, 定义数组,sizeof大小就是n*(n+1),右移两位实现除2操作。如果是python代码,可以用sum(range(1,n+1))
class Solution {
public:
int sumNums(int n) {
bool arr[n][n+1];
return sizeof(arr)>>1;
}
};
解法一:从循环做文章,由于循环就是相同的函数重复n次,创建类的对象会调用构造函数。利用这个性质创建n个类的对象即可。类中变量设定为static,这样就完成了对象间变量的继承。
//
// Created by Xue,Lin on 2020/7/7.
//
#ifndef UNTITLED_NSUM_H
#define UNTITLED_NSUM_H
// 利用定义n个类的对象,类的构造函数会被调用n次和static只会被分配一个空间的性质
class Temp{
public:
Temp() {++N; sum += N; }
static unsigned int getSum() { return sum; }
private:
static unsigned int N;
static unsigned int sum;
};
unsigned int Temp::N = 0; // 注意static初始化,不初始化好像是不分配空间
unsigned int Temp::sum = 0;
#endif //UNTITLED_NSUM_H
int main() {
int n = 10;
Temp* result = new Temp[n];
delete []result;
result = NULL;
cout << Temp::getSum() << endl; // static函数不需要对象,可以直接通过类名调用
return 0;
}
解法二:从递归出发,当前无法使用递归的原因是不能使用判断,因此不能终止。利用虚函数,定义基类和策略类对象,定义数组0位为基类对象,其余n-1位为策略类,进行调用,即可实现递归停止。
//
// Created by Xue,Lin on 2020/7/7.
//
#ifndef UNTITLED_NSUMDEC_H
#define UNTITLED_NSUMDEC_H
class A{ // 基类做递归的终止条件
public:
virtual unsigned int sum(unsigned int n, A* arr[])
{
return 0;
}
};
class B: public A{
public:
unsigned int sum(unsigned int n, A* arr[])
{
// !!是c++中一个运算符,当n不为0,!!n=1,当n=0,!!n=0
// arr是一个A类实例变量的二元数组,arr[0]指向A,arr[1]指向B
// 利用虚函数是指针指向实例时哪个类,就调用哪个类函数的特性
return arr[!!n]->sum(n-1, arr) + n;
}
};
#endif //UNTITLED_NSUMDEC_H
int main() {
A* arr[2];
A a;
B b;
arr[0] = &a;
arr[1] = &b;
int n = 5;
cout << b.sum(n, arr) << endl;
return 0;
}
解法三:利用函数指针,整体思想同解法二。
using namespace std;
typedef unsigned int (*func)(unsigned int);
unsigned int terminator(unsigned int n)
{
return 0;
}
unsigned int sum(unsigned int n)
{
func f[2] = {terminator, sum};
return n + f[!!n](n-1);
}
int main() {
int n = 10;
cout << sum(n) << endl;
return 0;
}
解法四:利用模板类型求解。这个方法需要n最开始为常量,且不能太大。先不研究。
leetcode官方解法
解法一:利用&运算符左值为false不会计算右值的特性,终止递归。
class Solution {
public:
int sumNums(int n) {
n && (n += sumNums(n - 1));
return n;
}
};
解法二:用加法和位运算来模拟乘法,叫做俄罗斯农民乘法,先不研究了。
面试题47:不用加减乘除做加法
写一个函数,求两个整数之和。要求在函数体内不能使用+,-,*,/ 运算符号
leetcode链接 https://leetcode-cn.com/problems/bu-yong-jia-jian-cheng-chu-zuo-jia-fa-lcof/class Solution { public: int add(int a, int b) { // 因为不能用加减乘除,只能用位运算 while(b != 0) { cout << "a: " << a << " b: " << b << endl; int sum = a ^ b; int car = ((unsigned int)(a & b) << 1); // 这里注意要转unsigned,不然负数会有问题 a = sum; b = car; }> return a; } };
解题思路:找到加法和二进制位运算之间的关系。注意负数。
先考虑两个数都是正数,譬如3+5
3的二进制是011,5的二进制是101,按位相加,不记进位,相加为110,进位为010,再次进行重复操作,不记进位100,进位100,相加不记进位000,记进位1000,最终结果为1000=8。按位相加,不记进位可以用位异或实现。进位可以用位与后左移一位实现。终止条件为进位为0。
考虑一正一负。-5和3
-5的二进制表示,在计算机中,数字的二进制是用补码表示的,正数的补码就是本身,负数的补码是绝对值取反+1,再加上符号位即可。5的8位二进制表示0000101,取反1111010,+1得1111011,加符号位11111011。3的二进制表示00000011,相加11111110,去符号位-1,得11111101,取反1000010,结果为-2。
两个负数,同样用负数补码进行操作,同上。
面试题48:不能被继承的类
用c++设计一个不能被继承的类 这道题没有平台有链接
// Created by Xue,Lin on 2020/7/7. // #ifndef UNTITLED_PRIVATECLASS_H #define UNTITLED_PRIVATECLASS_H class A{ friend class B; private: A() {}; ~A() {}; }; class B:virtual public A { public: B() {}; ~B() {}; }; #endif //UNTITLED_PRIVATECLASS_H
解题思路:
思路一:常规思路。把构造函数和析构函数定义为私有函数。定义共有静态函数来获取和释放类的实例。但是这样我们只能获得堆上的实例,不能获得栈上的实例
//
// Created by Xue,Lin on 2020/7/7.
//
#ifndef UNTITLED_PRIVATECLASS_H
#define UNTITLED_PRIVATECLASS_H
class A{
private:
A() {};
~A() {};
public:
static A* getA(){ A *a = new A(); return a; }
static void deleteA(A *a) {delete a;}
};
#endif //UNTITLED_PRIVATECLASS_H
思路二:使用虚拟继承。利用友元类可以调用基类的私有构造和析构函数,但是其余类不行的特性。 参考链接 https://blog.csdn.net/zhouwei1221q/article/details/45741701?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.nonecase
// Created by Xue,Lin on 2020/7/7.
//
#ifndef UNTITLED_PRIVATECLASS_H
#define UNTITLED_PRIVATECLASS_H
class A{
friend class B;
private:
A() {};
~A() {};
};
class B:virtual public A
{
public:
B() {};
~B() {};
};
#endif //UNTITLED_PRIVATECLASS_H
【c++拾遗】c++中友元
参考链接 https://www.cnblogs.com/Libinkai/p/10622473.html友元函数:友元函数是在类中使用关键字friend修饰的非成员函数
1)友元普通函数:友元函数是一个普通的函数,友元普通函数在实现时,不需要类名的限定;在调用时,也不需要由实例来调用。在类中定义的友元函数其实就是普通函数,而不是类的成员。
2)友元成员函数:友元函数是其它类的成员函数。必须先定义包含成员函数的类(比如说A),再在另外一个类(比如说B)中将该成员函数声明为友元函数。此时虽然这个友元函数是A的成员函数,该友元函数仍然称为非成员函数(对于B来说)友元类:1)友元关系是不能传递的,如A是B的友元,B是C的友元,但A不是C的友元 2)友元关系是单向的,A是B的友元,A可以访问B的私有属性,反之不成立 3) 友元关系是不被继承的,A是B的友元,但A的派生类不是B的友元
【c++拾遗】虚继承
参考链接 https://blog.csdn.net/longlovefilm/article/details/80558879
如果是普通继承关系,类D中就有了两份类A的成员。定义虚拟继承,就只有一份。