面试题10:矩形覆盖
我们可以用2 * 1的小矩形横着或者竖着去覆盖更大的矩形。请问n个2 * 1的小矩形无重叠地覆盖一个2 * n的大矩形,总共有多少种方法?
题意解释:
解题思路;
代码实现:
class Solution {
public:
int rectCover(int number) {
if(number < 0)
{
return -1;
}
int result[] = {0,1,2};
if(number < 3)
{
return result[number];
}
int a = 1;
int b = 2;
int c = 0;
int i = 3;
for(i;i<=number;i++)
{
c = a + b;
a = b;
b = c;
}
return c;
}
};
面试题11:二进制中1的个数
输入一个整数,输出该函数二进制表示中1的个数。其中负数用补码表示。
例如:把9表示成二进制是1001,有2位是1。因此,如果输入9,则该函数输出2。
补充知识:
位运算:
位运算是把数字用二进制表示之后,对每一位上0或者1的运算。
左移运算符m<<n表示把m左移n位。在左移n位的时候,最左边的n位将被丢弃,同时在最右边补上n个0.比如:
00001010 <<2=00101000 左移两位
10001010<<3=01010000左移三位
右移运算符m>>n表示把m右移n位。在右移n位的时候,最右边的n位将被丢弃。但右移时处理最左边位的情形要稍微复杂一点。如果数字是一个无符号数值,则用0填补最左边的n位;如果数字是一个有符号数值,则用数字的符号位填补最左边的n位。
00001010>>2=00000010(正数右移2位,直接在左边补2个0)
10001010>>3=11110001(负数右移3位,直接在左边补3个1)
解题思路:
先判断整数二进制表示中最右边的1位是不是1;接着把输入的整数右移一位,此时,原来处于从右边数起的第二位被移到最右边了,再判断是不是1;这样每移动一位,直到整个整数变成0为止。
现在的问题转化为如何判断整数最右边是不是1?
把整数和1做位运算看结果是不是0就知道了。1除最右边的一位之外所有位都为0。
如果该数与1做与运算,结果为1,则表示该位为1,结果为0,则表示该位为0。
代码实现:
int NumberOf1(int n)
{
int count=0;
while(n)
{
if(n&1)
count++;
n=n>>1;
}
return count;
}
代码实现:
int NumberOf1(int n)
{
int count=0;
unsigned int flag = 1;
while(flag)
{
if(n&flag)
count++;
flag=flag<<1;
}
return count;
}
优秀解法:
思路:把一个整数减去1,再和原整数做与运算,会把该整数做与运算,会把该整数最右边的1变成0。那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。
代码实现:
int NumberOf1(int n)
{
int count = 0;
while(n)
{
++count;
n=(n-1)&n;
}
return count;
}
面试题12:数值的整数次方
实现函数double Power(double base,int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
全面考虑边界条件:
当指数为负数的时候,可以先对指数求绝对值,算出次方的结果之后再取倒数。
既然要求倒数,就需要考虑底数是0且指数为负数的情况下,如果不进行特殊处理,就会出现对0求倒数,从而导致程序运行出错。
怎么告诉函数调用者出现了这种错误?
可以通过:返回值、全局变量、异常这三种方式,需要讨论这三种方式的优缺点,然后选择合适的方式。
由于0的0次方在数学上是没有意义的,因此无论输出是0还是1都是可以接受的,但这都需要和面试官说清楚,表明我们已经考虑到这个边界值了。
解题思路:
代码实现:
class Solution {
public:
double Power(double base, int exponent) {
if(exponent>0)
{
if(exponent==1)
return base;
if((exponent&0x1)==0)
// if(exponent%2==0)
return Power(base,exponent/2)*Power(base,exponent/2);
else
return Power(base,exponent/2)*Power(base,exponent/2+1);
}
else if (exponent==0)
{
return 1;
}
else
{
return 1/Power(base,0-exponent);
}
}
};
面试题13:调整数组顺序使奇数位于偶数前
解题思路:
声明两个指针,第一个指针初始化时指向数组的第一个数字,它只向后移动;第二个指针初始化时指向数组的最后一个数字,它只向前移动。在两个指针相遇之前,第一个指针总是位于第二个指针的前面。如果第一个指针指向的数字是偶数,并且第二个指针指向的数字是奇数,则交换这两个数字。
举例说明:
代码实现:
class Solution {
public:
void reOrderArray(vector<int> &array) {
//unsigned int length;
if(array.size() == nullptr)
{
return;
}
int *pBegin = arry.begin();
int *pEnd = array.size() - 1;
while(pBegin < pEnd)
{
//向后移动pBegin,直到它指向偶数
while(pBegin < pEnd && (*pBegin&0x1) != 0)
pBegin ++;
//向前移动pEnd,直到它指向奇数
while(pBegin < pEnd && (*pEnd & 0x1) == 0)
pEnd --;
if(pBegin < pEnd)
{
int temp = *pBegin;
*pBegin = *pEnd;
*pEnd = temp;
}
}
}
};
面试题14:链表中倒数第K个节点
struct ListNode
{
int m_nValue;
ListNode *m_pNext;
};
解题思路:
为了实现只遍历一次就能找到倒数第k个节点,我们可以定义两个指针。第一个指针从链表的头指针开始遍历向前走k-1,第二个指针保持不动;从第k步开始,第二个指针也开始从链表的头指针开始遍历。由于两个指针的距离保持在K-1,当第一个(走在前面的)指针到达链表的尾节点时,第二个指针(走在后面的)指针正好是倒数第k个结点。
注意检查代码的鲁棒性
代码实现:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
//如果输入的链表头指针为nullptr,那么整个链表为空,此时
//查找倒数第k个节点自然应该返回nullptr。
//如果输入的k是0,也就是试图查找倒数第0个节点,由于我们计数是从1开始的,因此输入0没有实际意义。
//也可以返回nullptr。
if(pListHead == nullptr || k == 0)
return nullptr;
ListNode *pAhead = pListHead;//第一个指针
ListNode *pBehind = nullptr;//第二个指针
for(unsigned int i = 0;i < k-1; i++)
{
//加for循环
if(pAhead->next!=nullptr)//如果链表的节点数少于k,那么在for循环中遍历链表可能回出现指向nullptr的next.
pAhead = pAhead->next;//第一个指针走k-1步
else{
return nullptr;
}
}
pBehind = pListHead;
while(pAhead->next!=nullptr )
{
//两个指针同时走
pAhead = pAhead->next;
pBehind = pBehind->next;
}
return pBehind;//返回第二个指针,即链表中倒数第k个节点。
}
};
面试题15:反转链表
代码实现:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
ListNode* pReversedHead = nullptr;
ListNode* pNode = pHead;
ListNode* pPrev = nullptr;
while(pNode != nullptr)
{
ListNode* pNext = pNode->next;
if(pNext == nullptr)
pReversedHead = pNode;
pNode->next = pPrev;
pPrev = pNode;
pNode = pNext;
}
return pReversedHead;
}
};