2.3.2字符串
面试题4:二维数组中的查找
题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否有该函数。
思路:在查找的过程中,首先选取数组中右上角的数字,如果要查找的数字不在数组的右上角,则每一次都在数组的查找范围中剔除一行或者一列,这样每一步都可以缩小查找范围,直到找到要查找的数字,或者查找范围为空。(书上的思路很清晰)
代码:
#include <iostream>
using namespace std;
bool Find(int* matrix,int rows, int columns,int number)
{
bool found = false;
if(matrix != nullptr && rows > 0 && columns > 0){
int row = 0;
int column = columns -1 ;
while (row < rows && column >= 0){
if (matrix[row*columns+column] == number){
found = true;
break;
}
else if(matrix[row*columns+column] > number)
--column;
else
++row;
}
}
return found;
}
void Test(char* testName, int* matrix, int rows, int columns, int number, bool expected)
{
if(testName != nullptr)
printf("%s begins: ", testName);
bool result = Find(matrix, rows, columns, number);
if(result == expected)
printf("Passed.\n");
else
printf("Failed.\n");
}
// 1 2 8 9
// 2 4 9 12
// 4 7 10 13
// 6 8 11 15
// 要查找的数在数组中
int main()
{
int matrix[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
Test("Test1", (int*)matrix, 4, 4, 7, true);
}
当然也可以首先选取数组中左下角的数字,这样子的话程序的条件要做一定的修改,但是基本的逻辑是不变的。PS:怎么能够利用二维数组的行和列来表示某个位置的元素,是比较关键的问题。
bool Find(int* matrix,int rows, int columns,int number)
{
bool found = false;
if(matrix != nullptr && rows > 0 && columns > 0){
int row = rows - 1;
int column = 0 ;
while (row < rows && column >= 0){
if (matrix[row*columns+column] == number){
found = true;
break;
}
else if(matrix[row*columns+column] < number)
++column;
else
--row;
}
}
return found;
}
字符串数组和字符指针的区别:
#include <iostream>
using namespace std;
int main()
{
char str1[] = "hello world";
char str2[] = "hello world";
char *str3 = "hello world";//同样的一个字符串,储存在常量区
char *str4 = "hello world";
if(str1 == str2)
{
cout<<"str1 and str2 are same"<<endl;
}
else{
cout<<"str1 and str2 are not same"<<endl;
}
if(str3 == str4){
cout<<"str3 and str4 are same"<<endl;
}
else{
cout<<"str3 and str4 are not same"<<endl;
}
}
存的都是“hello world”,字符数组st1和str2是不一样的,字符指针的st3和str4指向的是同一个字符常量区。
面试题5:替换空格
题目:请实现一个函数,把字符串中的每个空格替换成“%20”,例如输入“we are happy.”,则输出“we%20are%20happy.”
#include <iostream>
using namespace std;
void ReplaceBlank(char string[],int length)
{
if(string == nullptr || length <= 0)
return;
int originalLength = 0;
int numberOfBlank = 0;
int i = 0;
while(string[i] != '\0'){
++originalLength;
if(string[i] == ' ')//判断是否四空格,逻辑表达式啊
++numberOfBlank;
++i;
}
int newLength = originalLength + numberOfBlank*2;
if(newLength > length)
return;
int indexOfOriginal = originalLength;
int indexOfNew = newLength;
while (indexOfOriginal >= 0 && indexOfNew >indexOfOriginal){
if(string[indexOfOriginal] == ' ')
{
string[indexOfNew--] = '0';
string[indexOfNew--] = '2';
string[indexOfNew--] = '%';
}
else
string[indexOfNew--] = string[indexOfOriginal];
--indexOfOriginal;
}
}
int main()
{
char str[50] = "we are happy.";
ReplaceBlank(str,50);
cout<<str<<endl;
}
上面的测试程序只是一个简答的测试用例,不够完整。
2.3.3链表
不带头结点链表实现(插入和删除节点)
#include <iostream>
using namespace std;
// 首先写一个链表节点
struct ListNode{
int m_nValue;
ListNode* m_pNext;
};
// 往链表的末尾添加一个节点
void AddToTail(ListNode** pHead, int value)
{
ListNode* pNew = new ListNode();
pNew->m_nValue = value;
pNew->m_pNext = nullptr;
if(*pHead == nullptr){ //判断是否是空链表
*pHead = pNew;
}
else{
ListNode* pNode = *pHead;
while (pNode->m_pNext != nullptr)// 找到要插入的位置
pNode = pNode->m_pNext;
pNode->m_pNext = pNew;
}
}
void RemoveNode(ListNode**pHead, int value)
{
if(pHead == nullptr || *pHead == nullptr)
return;
ListNode* pToBeDeleted = nullptr;
if((*pHead)->m_nValue == value){
pToBeDeleted = *pHead;
*pHead = (*pHead)->m_pNext;
}
else{
ListNode* pNode = *pHead;
while (pNode->m_pNext != nullptr && pNode->m_pNext->m_nValue != value)
pNode = pNode->m_pNext;
if(pNode->m_pNext != nullptr && pNode->m_pNext->m_nValue == value){
pToBeDeleted = pNode->m_pNext;
pNode->m_pNext = pNode->m_pNext->m_pNext;
}
}
if(pToBeDeleted != nullptr){
delete pToBeDeleted;
pToBeDeleted = nullptr;
}
}
int main()
{
ListNode**p = nullptr;
ListNode*phead = nullptr;
p = &phead;
AddToTail(p,5);
AddToTail(p,4);
AddToTail(p,12);
AddToTail(p,11);
AddToTail(p,0);
RemoveNode(p, 0);
return 0;
}
面试题6:从尾到头打印链表
解法一:用栈来辅助实现
void PrintListReversingly_Iteratively(ListNode* pHead)
{
std::stack<ListNode*>nodes;
ListNode* pNode = pHead;
while (pNode != nullptr){
nodes.push(pNode);
pNode = pNode->m_pNext;
}
while (!nodes.empty()){
pNode = nodes.top();
printf("%d\t",pNode->m_nValue);
nodes.pop();
}
}
解法二:用递归来实现
void PrintListReversingly_Recursively(ListNode* pHead)
{
if(pHead != nullptr){
if(pHead->m_pNext != nullptr){
PrintListReversingly_Recursively(pHead->m_pNext);
}
printf("%d\t",pHead->m_nValue);
}
}
面试题7:重建二叉树
#include <iostream>
#include <exception>
struct BinaryTreeNOde
{
int my_nValue;
BinaryTreeNOde* m_pLeft;
BinaryTreeNOde* m_pRight;
};
BinaryTreeNOde* ConstructCore(int* sartPreorder, int* endPreorder, int* startInorder, int* endInorder);
BinaryTreeNOde * Construct(int* preorder, int* inorder, int length)
{
if(preorder == nullptr || inorder == nullptr || length <= 0 )
return nullptr;
return ConstructCore(preorder,preorder + length -1,inorder,inorder+length-1);
}
BinaryTreeNOde* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder)
{
int rootValue = startPreorder[0];
BinaryTreeNOde* root = new BinaryTreeNOde();
root->my_nValue = rootValue;
root->m_pLeft = root->m_pRight = nullptr;
if(startPreorder == endPreorder){
if(startInorder == endInorder && *startPreorder == *startInorder)
return root;
else
throw std::exception();//这个异常的抛出是怎么回事?
}
int* rootInorder = startInorder;
while (rootInorder <= endInorder && *rootInorder != rootValue)
++rootInorder;
if(rootInorder == endInorder && *rootInorder != rootValue)
throw std::exception();
int LeftLength = rootInorder - startInorder;
int *leftPreorderEnd = startPreorder + LeftLength;
if(LeftLength > 0)
{
root->m_pLeft = ConstructCore(startPreorder+1,leftPreorderEnd,startInorder,rootInorder-1);
}
if(LeftLength < endPreorder - startPreorder)
{
root->m_pRight = ConstructCore(leftPreorderEnd+1,endPreorder,rootInorder+1,endInorder);
}
return root;
}
面试题8:二叉树的下一个节点
#include <iostream>
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
BinaryTreeNode* m_pParent;
};
BinaryTreeNode* GetNext(BinaryTreeNode* pNode)
{
if(pNode == nullptr)
return nullptr;
BinaryTreeNode* pNext = nullptr;
if(pNode->m_pRight != nullptr)
{
BinaryTreeNode*pRight = pNode->m_pRight;
while(pRight->m_pLeft != nullptr)
pRight = pRight->m_pLeft;
pNext = pRight;
}
else if(pNode->m_pParent != nullptr)
{
BinaryTreeNode* pCurrent = pNode;
BinaryTreeNode* pParent = pNode->m_pParent;
while(pParent != nullptr && pCurrent == pParent->m_pRight)
{
pCurrent = pParent;
pParent = pParent->m_pParent;
}
pNext = pParent;
}
return pNext;
}
上面的代码根据当前节点有没有右子树,分了两种情况。没有右子树又分了两种情况,当前节点为父节点的左孩子,和当前节点为父亲节点的右孩子。
2.3.5栈和队列
面试题9:用两个栈实现队列
题目:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入节点和在队列头部删除节点的功能。
#include <iostream>
#include <stack>
#include <exception>
using namespace std;
//用两个栈来实现一个队列的代码
template <typename T>class CQueue
{
public:
CQueue(void){};
~CQueue(void){};
void appendTail(const T& element);
T deleteHead();
private:
stack<T> stack1;
stack<T> stack2;
};
template <typename T> void CQueue<T>::appendTail(const T &element)
{
stack1.push(element);
}
template <typename T>T CQueue<T>::deleteHead()
{
if(stack2.size() <= 0){
while (stack1.size()>0){
T& data = stack1.top();
stack1.pop();
stack2.push(data);
}
}
if(stack2.size() == 0)
throw new exception();
T head = stack2.top();
stack2.pop();
return head;
}
int main()
{
CQueue<int > myqueue;
for (int i = 0; i < 5; ++i) {
myqueue.appendTail(i);
}
for (int j = 0; j < 5; ++j) {
int k = myqueue.deleteHead();
cout<< k <<" ";
}
}
附加题:用两个队列实现一个栈
#include <iostream>
#include <queue>
#include <exception>
using namespace std;
//用两个队列来实现一个栈
template <typename T>class CStack
{
public:
CStack(void){};
~CStack(void){};
void appendTail(const T& element);
T deleteHead();
private:
queue<T> queue1;
queue<T> queue2;
};
template <typename T> void CStack<T>::appendTail(const T &element)
{
if(!queue1.empty() && !queue2.empty()){
}
else{
if(queue1.empty()){
queue2.push(element);
}
else{
queue1.push(element);
}
}
}
template <typename T>T CStack<T>::deleteHead()
{
if (queue1.empty() && queue2.empty()) {
//异常情况
throw new exception();
}
T head;
if (!queue1.empty()) {
while (queue1.size() > 1) {
T &data = queue1.front();
queue1.pop();
queue2.push(data);
}
head = queue1.front();
queue1.pop();
}
else {
while(queue2.size() > 1){
T& data = queue2.front();
queue2.pop();
queue1.push(data);
}
head = queue2.front();
queue2.pop();
}
return head;
}
void test(char actual, char expected)
{
if (actual == expected)
printf("Test passed.\n");
else
printf("Test failed.\n");
}
int main()
{
CStack<char> stack;
stack.appendTail('a');
stack.appendTail('b');
stack.appendTail('c');
char head = stack.deleteHead();
test(head, 'c');
head = stack.deleteHead();
test(head, 'b');
stack.appendTail('d');
head = stack.deleteHead();
test(head, 'd');
stack.appendTail('e');
head = stack.deleteHead();
test(head, 'e');
head = stack.deleteHead();
test(head, 'a');
//空栈删除,触发异常
//head = stack.deleteHead();
getchar();
return 0;
}
2.4.1递归和循环
#include <iostream>
using namespace std;
// 1+2+3+...+n的两种实现方式递归、循环
int AddFrom1ToN_Recursive(int n)
{
return n<=0 ? 0 : n + AddFrom1ToN_Recursive(n-1);
}
int AddFrom1ToN_Iterative(int n)
{
int result = 0;
for (int i = 0; i <= n ; ++i) {
result += i;
}
return result;
}
int main()
{
cout<<AddFrom1ToN_Recursive(100)<<endl;
cout<<AddFrom1ToN_Iterative(100)<<endl;
return 0;
}
面试题10:斐波那契数列
题目一:求菲波那契数列的第N项。
#include <iostream>
using namespace std;
long long Fibonacci_1(unsigned int n)
{
if(n <= 0){
return 0;
}
if(n == 1){
return 1;
}
return Fibonacci_1(n - 1 ) + Fibonacci_1(n - 2);
}
int main()
{
cout<<Fibonacci_1(100)<<endl;
return 0;
}
PS:按照作者的说法,试了一下求第100项的时候,真的是巨慢!!!此方法有大量的重复计算,并且递归的成熟也比较多。
#include <iostream>
using namespace std;
//求斐波那契数列的第N项
long long Fibonacci_2(unsigned int n)
{
int result[2] = {0 , 1};
if(n < 2){
return result[n];
}
long long fibNMinusOne = 1;
long long fibNMinusTwo = 0;
long long fibN = 0;
for (unsigned int i = 2; i <= n ; ++i) {
fibN = fibNMinusTwo + fibNMinusOne;
fibNMinusTwo = fibNMinusOne;
fibNMinusOne = fibN;
}
return fibN;
}
int main()
{
cout<<Fibonacci_2(100)<<endl;
return 0;
}
PS:没有比较就没有伤害,这种自下而上的方式,真的算的快多了。。。斐波那契数列的应用问题:青蛙跳台阶问题;用2*1小矩形覆盖2*8的大矩形,总共有多少种方法?
2.4.2查找和排序
剑指OFFER——快排的代码:
#include <stdio.h>
#include <stdlib.h>
int RandomInRange(int min, int max)
{
int random = rand() % (max - min + 1) + min;
return random;
}
void Swap(int* num1, int* num2)
{
int temp = *num1;
*num1 = *num2;
*num2 = temp;
}
int Partition(int data[], int length, int start, int end)
{
if(data == NULL || length <= 0 || start < 0 || end >= length) {
return -1;
}
int index = RandomInRange(start, end);
Swap(&data[index], &data[end]);
int small = start - 1;
for(index = start; index < end; ++ index)
{
if(data[index] < data[end])
{
++ small;
if(small != index)
Swap(&data[index], &data[small]);
}
}
++ small;
Swap(&data[small], &data[end]);
return small;
}
void QuickSort (int data[], int length, int start, int end) {
if (start == end) return;
int index = Partition(data, length, start, end);
if (index > start)
QuickSort(data, length, start, index-1);
if (index < end)
QuickSort(data, length, index+1, end);
}
int main(void)
{
int str[] = {49, 38, 65, 97, 76, 13, 27, 49};
QuickSort(str, 8, 0, 7);
for (int i : str) {
printf("%d ", i);
}
printf("\n");
return 0;
}
对公司中所有员工的年龄进行排序:
#include <iostream>
using namespace std;
// 对一个公司中所有员工的年龄进行排序
/*parameters:
* ages[]:the age of stuff
* length:the length of the ages[]
*/
void SortAges(int ages[], int length)
{
//对数组ages[]进行判断
if(ages == nullptr || length <= 0)
return;
const int oldestAge = 99;
//公司员工的年龄在0~99岁,所以timesOfAge[]数组的大小为100
int timesOfAge[oldestAge + 1];
//初始化数组timesOfAge[]
for (int i = 0; i <= oldestAge ; ++i) {
timesOfAge[i] = 0;
}
//ages[]中的元素为i就在timesOfAge[i]上加一,来统计年龄为i的人数
for (int j = 0; j < length; ++j) {
int age = ages[j];
if(age < 0 || age > oldestAge)
throw new std::exception();
++timesOfAge[age];
}
//遍历timesOfAge[]数组,某个年龄出现了多少次,就在数组ages[]里面设置几次年龄
int index = 0;
for (int k = 0; k <=oldestAge ; ++k) {
for (int i = 0; i < timesOfAge[k]; ++i) {
ages[index] = k;
++index;
}
}
}
int main()
{
int arr[] = {22,40,18,19,50,21,22,33,44,43};
int length = sizeof(arr) / sizeof(int);
SortAges(arr,length);
for (int i = 0; i < length; ++i) {
cout<<arr[i]<<" ";
}
}
面试题11:旋转数组的最小数字
数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,求该数组的最小值。
#include <iostream>
#include <exception>
using namespace std;
int MinInOrder(int* numbers, int index1, int index2);
int Min(int* numbers, int length)
{
if(numbers == nullptr || length <= 0)
throw new exception();
int index1 = 0;
int index2 = length - 1;
int indexMid = index1;
while (numbers[index1] >= numbers[index2])
{
if(index2 - index1 == 1){
indexMid = index2;
break;
}
indexMid = (index1 + index2) / 2;
if(numbers[index1] == numbers[index2] && numbers[indexMid] == numbers[index1])
return MinInOrder(numbers, index1, index2);
if(numbers[indexMid] >= numbers[index1])
index1 = indexMid;
else if(numbers[indexMid <= numbers[index2]])
index2 = indexMid;
}
return numbers[indexMid];
}
int MinInOrder(int* numbers, int index1, int index2)
{
int result = numbers[index1];
for (int i = index1 + 1; i <= index2 ; ++i) {
if(result > numbers[i])
result = numbers[i];
}
return result;
}
// ====================测试代码====================
void Test(int* numbers, int length, int expected)
{
int result = 0;
try
{
result = Min(numbers, length);
for(int i = 0; i < length; ++i)
printf("%d ", numbers[i]);
if(result == expected)
printf("\tpassed\n");
else
printf("\tfailed\n");
}
catch (...)
{
if(numbers == nullptr)
printf("Test passed.\n");
else
printf("Test failed.\n");
}
}
int main(int argc, char* argv[])
{
// 典型输入,单调升序的数组的一个旋转
int array1[] = { 3, 4, 5, 1, 2 };
Test(array1, sizeof(array1) / sizeof(int), 1);
// 有重复数字,并且重复的数字刚好的最小的数字
int array2[] = { 3, 4, 5, 1, 1, 2 };
Test(array2, sizeof(array2) / sizeof(int), 1);
// 有重复数字,但重复的数字不是第一个数字和最后一个数字
int array3[] = { 3, 4, 5, 1, 2, 2 };
Test(array3, sizeof(array3) / sizeof(int), 1);
// 有重复的数字,并且重复的数字刚好是第一个数字和最后一个数字
int array4[] = { 1, 0, 1, 1, 1 };
Test(array4, sizeof(array4) / sizeof(int), 0);
// 单调升序数组,旋转0个元素,也就是单调升序数组本身
int array5[] = { 1, 2, 3, 4, 5 };
Test(array5, sizeof(array5) / sizeof(int), 1);
// 数组中只有一个数字
int array6[] = { 2 };
Test(array6, sizeof(array6) / sizeof(int), 2);
// 输入nullptr
Test(nullptr, 0, 0);
return 0;
}
面试题12:矩阵中的路径
题目:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵任意一格开始,每一步都可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。
#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
bool hasPathCore(const char* matrix, int rows, int cols, int row, int col, const char* str, int& pathLength, bool* visited);
bool hasPath(const char* matrix, int rows, int cols, const char* str)
{
// 数组、字符串判空
if(matrix == nullptr || rows < 1 || cols < 1 || str == nullptr)
return false;
bool *visited = new bool[rows * cols];// 是否路过节点的布尔矩阵
memset(visited, 0, rows * cols);// 初始化布尔矩阵
int pathLength = 0;// 从字符串首开始
for (int row = 0; row < rows; ++row) {
for (int col = 0; col < cols; ++col) {
if(hasPathCore(matrix, rows, cols, row, col, str, pathLength, visited)){
return true;
}
}
}
delete[] visited;
return false;
}
bool hasPathCore(const char* matrix, int rows, int cols, int row, int col, const char* str, int& pathLength, bool* visited)
{
if(str[pathLength] == '\0')
return true;
bool hasPath = false;
int index = row*cols + col;
if(row >= 0 && row < rows && col >= 0 && col < cols && matrix[index] == str[pathLength] && !visited[index]) {
++pathLength;
visited[index] = true;
// 矩阵第n字符位置(row, col)上下左右四个点是否能找到字符串中n+1个字符
hasPath = hasPathCore(matrix, rows, cols, row, col - 1, str, pathLength, visited)
|| hasPathCore(matrix, rows, cols, row - 1, col, str, pathLength, visited)
|| hasPathCore(matrix, rows, cols, row, col + 1, str, pathLength, visited)
|| hasPathCore(matrix, rows, cols, row + 1, col, str, pathLength, visited);
// 找不到第n+1个字符,则回溯重新定位第n个字符
if (!hasPath) {
--pathLength;
visited[index] = false;
}
}
return hasPath;
}
// ====================测试代码====================
void Test(const char* testName, const char* matrix, int rows, int cols, const char* str, bool expected)
{
if(testName != nullptr)
printf("%s begins: ", testName);
if(hasPath(matrix, rows, cols, str) == expected)
printf("Passed.\n");
else
printf("FAILED.\n");
}
//ABTG
//CFCS
//JDEH
//BFCE
void Test1()
{
const char* matrix = "ABTGCFCSJDEH";
const char* str = "BFCE";
Test("Test1", (const char*) matrix, 3, 4, str, true);
}
//ABCE
//SFCS
//ADEE
//SEE
void Test2()
{
const char* matrix = "ABCESFCSADEE";
const char* str = "SEE";
Test("Test2", (const char*) matrix, 3, 4, str, true);
}
//ABTG
//CFCS
//JDEH
//ABFB
void Test3()
{
const char* matrix = "ABTGCFCSJDEH";
const char* str = "ABFB";
Test("Test3", (const char*) matrix, 3, 4, str, false);
}
//ABCEHJIG
//SFCSLOPQ
//ADEEMNOE
//ADIDEJFM
//VCEIFGGS
//SLHECCEIDEJFGGFIE
void Test4()
{
const char* matrix = "ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS";
const char* str = "SLHECCEIDEJFGGFIE";
Test("Test4", (const char*) matrix, 5, 8, str, true);
}
//ABCEHJIG
//SFCSLOPQ
//ADEEMNOE
//ADIDEJFM
//VCEIFGGS
//SGGFIECVAASABCEHJIGQEM
void Test5()
{
const char* matrix = "ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS";
const char* str = "SGGFIECVAASABCEHJIGQEM";
Test("Test5", (const char*) matrix, 5, 8, str, true);
}
//ABCEHJIG
//SFCSLOPQ
//ADEEMNOE
//ADIDEJFM
//VCEIFGGS
//SGGFIECVAASABCEEJIGOEM
void Test6()
{
const char* matrix = "ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS";
const char* str = "SGGFIECVAASABCEEJIGOEM";
Test("Test6", (const char*) matrix, 5, 8, str, false);
}
//ABCEHJIG
//SFCSLOPQ
//ADEEMNOE
//ADIDEJFM
//VCEIFGGS
//SGGFIECVAASABCEHJIGQEMS
void Test7()
{
const char* matrix = "ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS";
const char* str = "SGGFIECVAASABCEHJIGQEMS";
Test("Test7", (const char*) matrix, 5, 8, str, false);
}
//AAAA
//AAAA
//AAAA
//AAAAAAAAAAAA
void Test8()
{
const char* matrix = "AAAAAAAAAAAA";
const char* str = "AAAAAAAAAAAA";
Test("Test8", (const char*) matrix, 3, 4, str, true);
}
//AAAA
//AAAA
//AAAA
//AAAAAAAAAAAAA
void Test9()
{
const char* matrix = "AAAAAAAAAAAA";
const char* str = "AAAAAAAAAAAAA";
Test("Test9", (const char*) matrix, 3, 4, str, false);
}
//A
//A
void Test10()
{
const char* matrix = "A";
const char* str = "A";
Test("Test10", (const char*) matrix, 1, 1, str, true);
}
//A
//B
void Test11()
{
const char* matrix = "A";
const char* str = "B";
Test("Test11", (const char*) matrix, 1, 1, str, false);
}
void Test12()
{
Test("Test12", nullptr, 0, 0, nullptr, false);
}
int main(int argc, char* argv[])
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
Test7();
Test8();
Test9();
Test10();
Test11();
Test12();
return 0;
}
面试题13:机器人的运动范围
题目:地上有一个m行n列的方格。一个机器人从坐标(0,0)开始移动,它每次可以向左、右、上、下移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。例如当k = 18的时候可以进入(35,37)的格子,但是不能进入(35,38)的格子。请问机器人能够到达多少个格子?
#include <cstdio>
int movingCountCore(int threshold, int rows, int cols, int row, int col, bool* visited);
bool check(int threshold, int rows, int cols, int row, int col, const bool* visited);
int getDigitSum(int number);
// 这个题要求的是能达到的符合条件的所有格子的数目,有些理解为什么这么写了!
int movingCount(int threshold, int rows, int cols)
{
if(threshold < 0 || rows <= 0 || cols <= 0)
return 0;
bool *visited = new bool[rows * cols];// 建一个矩阵大小的bool矩阵
// 初始化矩阵
for (int i = 0; i < rows * cols; ++i) {
visited[i] = false;
}
int count = movingCountCore(threshold, rows, cols, 0, 0, visited);
delete [] visited;// 防止内存泄漏
return count;
}
int movingCountCore(int threshold, int rows, int cols, int row, int col, bool* visited)
{
int count = 0;
if(check(threshold,rows, cols, row, col, visited))// 判断传进来的(row,col)是否符合约束
{
visited[row * cols + col] = true;// 符合的话,相应的bool矩阵置1
count = 1 + movingCountCore(threshold, rows, cols,
row - 1, col, visited)
+ movingCountCore(threshold, rows, cols,
row, col - 1, visited)
+ movingCountCore(threshold, rows, cols,
row + 1, col, visited)
+ movingCountCore(threshold, rows, cols,
row, col + 1, visited);
}
return count;
}
// 判断是否符合约束的函数
bool check(int threshold, int rows, int cols, int row, int col, const bool* visited)
{
return row >= 0 && row < rows && col >= 0 && col < cols && getDigitSum(row) + getDigitSum(col) <= threshold
&& !visited[row * cols + col];
}
// 求一个输入的整数的各个数位之和
int getDigitSum(int number)
{
int sum = 0;
while(number > 0)
{
sum += number % 10;
number /= 10;
}
return sum;
}
// ====================测试代码====================
void test(char* testName, int threshold, int rows, int cols, int expected)
{
if(testName != nullptr)
printf("%s begins: ", testName);
if(movingCount(threshold, rows, cols) == expected)
printf("Passed.\n");
else
printf("FAILED.\n");
}
// 方格多行多列
void test1()
{
test("Test1", 5, 10, 10, 21);
}
// 方格多行多列
void test2()
{
test("Test2", 15, 20, 20, 359);
}
// 方格只有一行,机器人只能到达部分方格
void test3()
{
test("Test3", 10, 1, 100, 29);
}
// 方格只有一行,机器人能到达所有方格
void test4()
{
test("Test4", 10, 1, 10, 10);
}
// 方格只有一列,机器人只能到达部分方格
void test5()
{
test("Test5", 15, 100, 1, 79);
}
// 方格只有一列,机器人能到达所有方格
void test6()
{
test("Test6", 15, 10, 1, 10);
}
// 方格只有一行一列
void test7()
{
test("Test7", 15, 1, 1, 1);
}
// 方格只有一行一列
void test8()
{
test("Test8", 0, 1, 1, 1);
}
// 机器人不能进入任意一个方格
void test9()
{
test("Test9", -10, 10, 10, 0);
}
int main(int agrc, char* argv[])
{
test1();
test2();
test3();
test4();
test5();
test6();
test7();
test8();
test9();
return 0;
}
面试题14:剪绳子
题目:给你一根长度为n 的绳子,请把绳子剪成m段(m和n都是整数,n>1并且m>1),每根绳子的长度记为k[0],k[1],...k[m]。请问k[0]*k[1]*...k[m]可能的最大乘积是多少
#include <iostream>
#include <cmath>
using namespace std;
// ====================动态规划====================
int maxProductAfterCutting_solution1(int length)
{
if(length < 2)
return 0;
if(length == 2)
return 1;
if(length == 3)
return 2;
// 子问题的最优解存在数组products里。数组中第i个元素表示把长度为i的绳子剪成若干段之后
// 各段长度乘积的最大值
int* products = new int[length + 1];
products[0] = 0;
products[1] = 1;
products[2] = 2;
products[3] = 3;
int max = 0;
for (int i = 4; i <= length ; ++i) {
max = 0;
for (int j = 1; j <=i/2; ++j) {
int product = products[j] * products[i-j];
if(max < product)
max = product;
products[i] = max;
}
}
max = products[length];
delete [] products;
return max;
}
// ====================贪婪算法====================、
int maxProductAfterCutting_solution2(int length)
{
if(length < 2)
return 0;
if(length == 2)
return 1;
if(length == 3)
return 2;
// 尽可能多地减去长度为3的绳子段
int timesOf3 = length / 3;
// 当绳子最后剩下的长度为4的时候,不能再剪去长度为3的绳子段。
// 此时更好的方法是把绳子剪成长度为2的两段,因为2*2 > 3*1。
if(length - timesOf3 * 3 == 1)
timesOf3 -= 1;
int timesOf2 = (length - timesOf3 * 3) / 2;
return (int)(pow(3,timesOf3)) * (int)(pow(2, timesOf2));
}
// ====================测试代码====================
void test(const char* testName, int length, int expected)
{
int result1 = maxProductAfterCutting_solution1(length);
if(result1 == expected)
std::cout << "Solution1 for " << testName << " passed." << std::endl;
else
std::cout << "Solution1 for " << testName << " FAILED." << std::endl;
int result2 = maxProductAfterCutting_solution2(length);
if(result2 == expected)
std::cout << "Solution2 for " << testName << " passed." << std::endl;
else
std::cout << "Solution2 for " << testName << " FAILED." << std::endl;
}
void test1()
{
int length = 1;
int expected = 0;
test("test1", length, expected);
}
void test2()
{
int length = 2;
int expected = 1;
test("test2", length, expected);
}
void test3()
{
int length = 3;
int expected = 2;
test("test3", length, expected);
}
void test4()
{
int length = 4;
int expected = 4;
test("test4", length, expected);
}
void test5()
{
int length = 5;
int expected = 6;
test("test5", length, expected);
}
void test6()
{
int length = 6;
int expected = 9;
test("test6", length, expected);
}
void test7()
{
int length = 7;
int expected = 12;
test("test7", length, expected);
}
void test8()
{
int length = 8;
int expected = 18;
test("test8", length, expected);
}
void test9()
{
int length = 9;
int expected = 27;
test("test9", length, expected);
}
void test10()
{
int length = 10;
int expected = 36;
test("test10", length, expected);
}
void test11()
{
int length = 50;
int expected = 86093442;
test("test11", length, expected);
}
int main(int agrc, char* argv[])
{
test1();
test2();
test3();
test4();
test5();
test6();
test7();
test8();
test9();
test10();
test11();
return 0;
}
PS:使用动态规划贪婪法解决问题,值得总结和参考学习。
面试题15:二进制中1的个数
题目描述:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如,把9表示成二进制是1001,有2位是1。因此如果输入9 ,则该函数输出2。
可能引起死循环的解法
int NumberOf1(int n)
{
int count = 0;
while (n)
{
if(n & 1)
count++;
n = n >> 1;
}
return count;
}
输入的数n在右移的时候,如果是一个无符号的数值,则用0来补最左边的n位;如果数字原先是一个有符号的数字,则用数字的符号位填补最左边的n位。所以上面的这种写法会导致无限循环。我尝试将函数的形参改为unsigned int 类型之后,上面的函数就可以正常工作了。
常规解法
int NumberOf1(int n)
{
int count = 0;
unsigned int flag = 1;
while (flag)
{
if(n & flag)
count++;
flag = flag << 1;
}
return count;
}
这种解法不是让输入的数n来移动,而是让1来移动,然后做与运算。循环的次数就等于输入的二进制数的位数
高级解法
int NumberOf1(int n)
{
int count = 0;
while (n)
{
++count;
n = (n -1)&n;
}
return count;
}
这种解法巧妙的利用位运算的性质,解决了循环次数的问题,提高了循环的效率。嗯,是一种很牛掰的解法。
拓展题
用一条语句来判断输入的数,是不是2的整数次幂,其实就是判断其二进制表示中,是不是只有一个1.
bool JudgeNumIsMultipleOf2(int n)
{
// if(((n -1)&n) == 0)
// return true;
// else
// return false;
return ((n - 1) & n) == 0;
}
输入两个整数m和n,那么需要改变m二进制中表示的多少位,才能得到n。先做两个数的异或运算,再对得到的结果做二进制中1的个数的统计。
#include <iostream>
int NumberOf1(int n)
{
int count = 0;
while (n)
{
++count;
n = (n -1)&n;
}
return count;
}
int Judge(int n, int m)
{
int result = m ^ n;
return NumberOf1(result);
}
int main()
{
std::cout<<Judge(10,13)<< std::endl;
return 0;
}