您的位置:首页 > Web前端

剑指offer 试题11~20

2017-12-06 12:31 423 查看

试题11:旋转数组的最小数字

这题当时没想到思路,看的《剑指offer》

class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
if(rotateArray.size() == 0)
return 0;

int l = 0, r = rotateArray.size() - 1;
int mid = l;
while(rotateArray[l] >= rotateArray[r])
{
if(r - l == 1)
{
mid = r;
break;
}
mid = (l + r) >> 1;
if(rotateArray[l] == rotateArray[mid] && rotateArray[mid] == rotateArray[r])
{
int ans = INT_MAX;
for(int i = l; i <= r; ++i)
ans = min(ans, rotateArray[i]);
return ans;
}
if(rotateArray[l] <= rotateArray[mid])
l = mid;
else if(rotateArray[mid] <= rotateArray[r])
r = mid;
}
return rotateArray[mid];
}
};


试题12:矩阵中的路径

简单的dfs,从二维矩阵的每个点进行一次dfs,和目标串尝试进行匹配

写了两个稍有不同的写法

写法一:

class Solution {
public:
bool hasPath(char* matrix, int rows, int cols, char* str)
{
vector<bool> vis(rows * cols, 0);
for(int i = 0; i < rows; ++i)
for(int j = 0; j < cols; ++j)
{
if(matrix[i*cols+j] == *str)
{
vis[i*cols+j] = true;
if(dfs(matrix, rows, cols, str+1, i, j, vis))
return true;
vis[i*cols+j] = false;
}
}
return false;
}

bool dfs(char *matrix, int rows, int cols, char *str, int x, int y, vector<bool> &vis)
{
int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};
if(*str == '\0')
return true;
for(int i = 0; i < 4; ++i)
{
int nx = x + dx[i], ny = y + dy[i];
if(nx >= 0 && nx < rows && ny >= 0 && ny < cols && vis[nx*cols+ny] == false && matrix[nx*cols+ny] == *str)
{
vis[nx*cols+ny] = true;
if(dfs(matrix, rows, cols, str+<
115f6
span class="hljs-number">1, nx, ny, vis))
return true;
vis[nx*cols+ny] = false;
}
}
return false;
}
};


写法二:

class Solution {
public:
bool hasPath(char* matrix, int rows, int cols, char* str)
{
vector<bool> vis(rows * cols, 0);
for(int i = 0; i < rows; ++i)
for(int j = 0; j < cols; ++j)
if(dfs(matrix, rows, cols, str, i, j, vis))
return true;
return false;
}
bool dfs(char *matrix, int rows, int cols, char *str, int x, int y, vector<bool> &vis)
{
int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};
if(matrix[x*cols+y] != *str)
return false;
if(*(str+1) == '\0')
return true;
vis[x*cols+y] = true;
for(int i = 0; i < 4; ++i)
{
int nx = x + dx[i], ny = y + dy[i];
if(nx >= 0 && nx < rows && ny >= 0 && ny < cols && vis[nx*cols+ny] == false)
{
if(dfs(matrix, rows, cols, str+1, nx, ny, vis))
return true;
}
}
vis[x*cols+y] = false;
return false;
}
};


试题13:机器人的运动范围

一个简单的bfs

class Solution {
public:
int movingCount(int threshold, int rows, int cols)
{
int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};//用来控制从当前位置向上下左右移动
using pii = pair<int, int>;
queue<pii> que;
vector<bool> vis(rows*cols, 0);
int ans = 0;
if(decompose(0) + decompose(0) <= threshold)
{
que.emplace(pii(0, 0));
vis[0*cols+0] = true;
++ans;
}
while(! que.empty())
{
pii p = que.front();
que.pop();
for(int i = 0; i < 4; ++i)
{
int nx = p.first + dx[i], ny = p.second + dy[i];
if(nx >= 0 && nx < rows && ny >= 0 && ny < cols &&
vis[nx*cols+ny] == false && decompose(nx) + decompose(ny) <= threshold)
{
que.emplace(pii(nx, ny));
vis[nx*cols+ny] = true;
++ans;
}
}
}
return ans;
}
int decompose(int n)
{
int ans = 0;
while(n)
{
ans += n % 10;
n /= 10;
}
return ans;
}
};


试题14:剪绳子

绳子长度为2、3的时候特判。之后,让剪出的绳子尽可能的长度为3,如果最后绳子长度剩余为1,那么应该和倒数第二段绳子合在一起,剪成两个长度为2的更优

class Solution {
public:
int getMaxProduct(int length)
{
if(length < 2)
return 0;
if(length == 2)
return 1;
if(length == 3)
return 2;
int num3 = length / 3;
if(length - num3 * 3 == 1)
--num3;
int num2 = (length - num3*3) / 2;
int ans = 1;
for(int i = 0; i < num2; ++i)
ans *= 2;
for(int i = 0; i < num3; ++i)
ans *= 3;
return ans;
}
};


试题15:二进制中1的个数

谨记负数在内存中的表示方式,负数左移补0,右移补1。

解法一:用一个变量初始化为1,每次左移1位与数字进行 & 运算,判断当前位置是否为1

class Solution {
public:
int  NumberOf1(int n) {
int f = 1;
int cnt = 0;
int tot = 32;
while(tot--)
{
if(n & f)
++cnt;
f <<= 1;
}
return cnt;
}
};


解法二:很巧妙,每次令n = n & (n-1),这样每次去掉最右边的二进制1,记录循环次数即可

class Solution {
public:
int  NumberOf1(int n) {
int cnt = 0;
while(n)
{
++cnt;
n = n & (n-1);
}
return cnt;
}
};


试题16:数值的整数次方

偷懒直接用pow就好,或者用牛顿迭代法是更好的选择,这里按照书上写的

class Solution {
public:
double Power(double base, int exponent) {
const double eps = 1e-8;
if(exponent == 0)
return 1;
if(fabs(base - 0) < eps)//此处,当base=0且exponent<0是无解的,这里也返回了0,牛客里应该没有这样的数据
return 0;
double ans = fast_power(base, abs(exponent));
if(exponent < 0)
ans = 1.0 / ans;
return ans;
}
double fast_power(double base, int exponent)
{
double ans = 1.0;
while(exponent)
{
if(exponent & 1)
ans *= base;
exponent >>= 1;
base *= base;
}
return ans;
}
};


试题17:打印从1到最大的n位数

这个题牛客上面没有,自己写了一下,模拟一个大整数每次加上1,这里大整数的储存方式从左到右依次为从低位到高位,输出的时候要倒着输出

class Solution
{
public:
void Print1ToMaxOfDigits(int n)
{
if(n == 0)
return;
int len = n + 1;
char *str = new char[len];
for(int i = 0; i < len; ++i)
str[i] = '0';

int tot = 1;//大整数的长度
while(true)
{
int val = 1;
for(int i = 0; i < len && val != 0; ++i)
{
val += str[i]-'0';
str[i] = val%10 + '0';
val /= 10;
tot = max(tot, i+1);
}
if(tot-1 == n)//长度比n大的时候,结束循环
break;
for(int i = tot-1; i >= 0; --i)
printf("%c", str[i]);
printf("\n");
}
delete [] str;
}
};


另外一种解法,用数字排列的方式

class Solution
{
public:
void Print1ToMaxOfDigits(int n)
{
if(n <= 0)
return;
char *numbers = new char[n+1];
numbers
= '\0';
for(int i = 0; i < 10; ++i)
{
numbers[0] = i + '0';
dfs(numbers, n, 1);
}
delete [] numbers;
}
private:
void dfs(char *numbers, int len, int index)
{
if(index == len)
{
while(*numbers == '0' && *numbers != '\0')//去掉前导0
++numbers;
if(*numbers != '\0')
printf("%s\n", numbers);
return;
}
for(int i = 0; i < 10; ++i)
{
numbers[index] = i + '0';
dfs(numbers, len, index+1);
}
}
};


试题18:删除链表的节点

这道题牛客上也没有,自己写了一下,主要考虑一下情况:

要删除节点就是第一个节点时,那么把头往后面移一位即可

要删除节点就是尾节点时,那么从头遍历找到它的前驱,把前驱置为尾节点

否则,把要删除节点的下一个节点的值赋给要删除节点,把要删除节点的指向它后继的后继,那么此时要删除节点就和它的后继相当于完成了交换,删除它的后继即可,即O(1)删除

另外注意链表为空的情况

/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
//主题代码
class Solution {
public:
ListNode* deleteNode(ListNode* pHead, ListNode *pDeleted)
{
if(pHead == nullptr)
return nullptr;
if(pDeleted == nullptr)
return pHead;
if(pHead == pDeleted)
pHead = pHead->next;
else
{
if(pDeleted->next != nullptr)
{
ListNode *ptr = pDeleted;
pDeleted = pDeleted->next;
ptr->val = ptr->next->val;
ptr->next = ptr->next->next;
}
else
{
ListNode *ptr = pHead;
while(ptr->next != pDeleted)
ptr = ptr->next;
ptr->next = nullptr;
}
}
delete pDeleted;
return pHead;
}
};
/*
//以下为测试部分
//逆序生成链表
pair<ListNode*, ListNode*> work()
{
ListNode *pHead = nullptr;
ListNode *pDeleted = nullptr;
for(int i = 1; i <= 1; ++i)
{
ListNode *ptr = new ListNode(i);
ptr->next = pHead;
pHead = ptr;
if(i == 1) pDeleted = pHead;
}
return make_pair(pHead, pDeleted);
}
//打印链表
void print(ListNode *pHead)
{
while(pHead != nullptr)
{
printf("%d ", pHead->val);
pHead = pHead->next;
}
puts("");
}
*/


删除链表中重复的节点

例如 2 3 3 5 6 6 7,结果应该是 2 5 7

/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if(pHead == nullptr)
return nullptr;
ListNode *pNode = pHead, *preNode = nullptr;
while(pNode != nullptr)
{
ListNode *temp = pNode;
while(pNode->next != nullptr && pNode->val == pNode->next->val)
pNode = pNode->next;
if(temp != pNode)
{
pNode = pNode->next;
if(preNode == nullptr)
pHead = pNode;
else
preNode->next = pNode;
while(temp != pNode)
{
ListNode *p = temp;
temp = temp->next;
delete p;
}
}
else
{
preNode = pNode;
pNode = pNode->next;
}
}
return pHead;
}
};


试题19:正则表达式匹配

用递归求解,注意细节

class Solution {
public:
bool match(char* str, char* pattern)
{
if(str == nullptr || pattern == nullptr)
return false;

return dfs(str, pattern);
}
private:
bool dfs(char *str, char *pattern)
{
if(*str != '\0' && *pattern == '\0')
return false;
if(*str == '\0' && *pattern == '\0')
return true;
if(*(pattern+1) == '*')
{
if((*pattern == '.' && *str != '\0') || *pattern == *str)
return dfs(str+1, pattern+2) || dfs(str, pattern+2) || dfs(str+1, pattern);
else
return dfs(str, pattern+2);
}
else
{
if((*pattern == '.' && *str != '\0') || *pattern == *str)
return dfs(str+1, pattern+1);
else
return false;
}
}
};


试题20:表示数值的字符串

剑指offer上的写法很好,注意细节

class Solution {
public:
bool isNumeric(char* string)
{
if(string == nullptr)
return false;
bool flag = scanInt(string);
if(*string == '.')
{
++string;
flag = scanUnsignInt(string) || flag;
}
if(*string == 'e' || *string == 'E')
{
++string;
flag = scanInt(string) && flag;
}
return flag && *string == '\0';
}
private:
bool scanInt(char* &str)
{
if(*str == '+' || *str == '-')
++str;
return scanUnsignInt(str);
}
bool scanUnsignInt(char* &str)
{
char *temp = str;
while(*str != '\0' && isdigit(*str))
++str;
return str != temp;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: