24. 机器人的运动范围
地上有一个 m 行和 n 列的方格,横纵坐标范围分别是 0∼m−1 和 0∼n−1。
一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格。
但是不能进入行坐标和列坐标的数位之和大于 k 的格子。
请问该机器人能够达到多少个格子?
样例1
输入:k=7, m=4, n=5
输出:20
样例2
输入:k=18, m=40, n=40
输出:1484
解释:当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。
但是,它不能进入方格(35,38),因为3+5+3+8 = 19。
注意:
0<=m<=50
0<=n<=50
0<=k<=100
class Solution {
public:
int get_single_sum(int x)
{
int s = 0;
while(x) s += x % 10, x /= 10;
return s;
}
int get_sum(pair<int, int> p)
{
return get_single_sum(p.first) + get_single_sum(p.second); //一个点两个数
}
int movingCount(int threshold, int rows, int cols)
{
int res = 0;
if(!rows || !cols) return 0;
vector<vector<bool>> st(rows, vector<bool>(cols));
queue<pair<int, int>>q;
q.push({0,0});
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
while(q.size())
{
auto t = q.front(); //每次取出队头
q.pop();
if(get_sum(t) > threshold || st[t.first][t.second]) continue; //判断当前点有没有被遍历过
res ++;
st[t.first][t.second] = true;
for(int i = 0; i < 4; i ++)
{
int x = t.first + dx[i], y = t.second + dy[i];
if(x >= 0 && x < rows && y >= 0 && y < cols)
{
q.push({x, y});
}
}
}
return res;
}
};
25. 剪绳子
给你一根长度为 n 绳子,请把绳子剪成 m 段(m、n 都是整数,2≤n≤58 并且 m≥2)。
每段的绳子的长度记为k[0]、k[1]、……、k[m]。k[0]k[1] … k[m] 可能的最大乘积是多少?
例如当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到最大的乘积18。
样例
输入:8
输出:18
class Solution {
public:
int maxProductAfterCutting(int n) {
//拆成多个3,最多两个2
if(n <= 3) return 1 * (n - 1);
int res = 1;
if(n % 3 == 1) res *= 4, n -= 4;
if(n % 3 == 2) res *= 2, n -= 2;
while(n) res *= 3, n -= 3;
return res;
}
};
26. 二进制中1的个数
输入一个32位整数,输出该数二进制表示中1的个数。
注意:
负数在计算机中用其绝对值的补码来表示。
样例1
输入:9
输出:2
解释:9的二进制表示是1001,一共有2个1。
样例2
输入:-2
输出:31
解释:-2在计算机里会被表示成11111111111111111111111111111110,
一共有31个1。
class Solution {
public:
int NumberOf1(int _n) {
unsigned int n = _n; //无符号整数右移后高位补上0,有符号整数右移高位补上1
int s = 0;
while(n) s += n & 1, n >>= 1; //取个位计算1的个数,右移删掉最低位
return s;
}
};
27. 数值的整数次方
实现函数double Power(double base, int exponent),求base的 exponent次方。
不得使用库函数,同时不需要考虑大数问题。
注意:
不会出现底数和指数同为0的情况
样例1
输入:10 ,2
输出:100
样例2
输入:10 ,-2
输出:0.01
class Solution {
public:
double Power(double base, int exponent) {
double res = 1;
for(int i = 0; i < abs(exponent); i ++) res *= base;
if(exponent < 0) res = 1 / res;
return res;
}
};
28. 在O(1)时间删除链表结点
给定单向链表的一个节点指针,定义一个函数在O(1)时间删除该结点。
假设链表一定存在,并且该节点一定不是尾节点。
样例
输入:链表 1->4->6->8
删掉节点:第2个节点即6(头节点为第0个节点)
输出:新链表 1->4->8
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
node ->val = node->next->val;
node->next = node->next->next;
}
};
29. 删除链表中重复的节点
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留。
样例1
输入:1->2->3->3->4->4->5
输出:1->2->5
样例2
输入:1->1->1->2->3
输出:2->3
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* head) {
auto dummy = new ListNode(-1);
dummy->next = head;
auto p = dummy;
while(p->next)
{
auto q = p->next;
while(q && p->next->val == q->val) q = q->next;
if(p->next->next == q) p = p->next;
else p->next = q;
}
return dummy->next;
}
};
30. 正则表达式匹配
请实现一个函数用来匹配包括’.‘和’*'的正则表达式。
模式中的字符’.‘表示任意一个字符,而’*'表示它前面的字符可以出现任意次(含0次)。
在本题中,匹配是指字符串的所有字符匹配整个模式。
例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配。
样例
输入:
s=“aa”
p=“a*”
输出:true
/*
动态规划DP
状态表示:f[i][j] 第一串从第i个字母到最后,和第二串从第j个字母到最后 相匹配
状态转移:
1.p[j]是正常字符,f[i][j] == s[i] == p[j] && f[i + 1][j + 1]
2.p[j]是'.', f[i][j] = f[i + 1][j + 1]
3.p[j + 1]是'*', f[i][j] = f[i][j + 2](前面字符出现0次) || f[i + 1][j] (前面字符是不是能更当前*位匹配)
f[n][m] = true
*/
class Solution {
public:
int n, m;
vector<vector<int>> f;
string s, p;
bool isMatch(string _s, string _p) {
s = _s, p = _p;
n = s.size(), m = p.size();
f = vector<vector<int>>(n + 1, vector<int>(m + 1, -1));
return dp(0, 0);
}
bool dp(int x, int y)
{
if(f[x][y] != -1) return f[x][y];
if(y == m) return f[x][y] = x == n;
bool first_match = x < n && (s[x] == p[y] || p[y] == '.'); //顺序
if(y + 1 < m && p[y + 1] == '*')
{
f[x][y] = dp(x, y + 2) || first_match && dp(x + 1, y); //增加对first_match的判断
}
else
{
f[x][y] = first_match && dp(x + 1, y + 1);
}
return f[x][y];
}
};
31. 表示数值的字符串
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。
但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。
注意:
小数可以没有整数部分,例如.123等于0.123;
小数点后面可以没有数字,例如233.等于233.0;
小数点前面和后面可以有数字,例如233.666;
当e或E前面没有数字时,整个字符串不能表示数字,例如.e1、e1;
当e或E后面没有整数时,整个字符串不能表示数字,例如12e、12e+5.4;
样例:
输入: “0”
输出: true
class Solution {
public:
bool isNumber(string s) {
//消除空格
int i = 0, j = s.size();
while(i <= j && s[i] == ' ') i ++;
while(i <= j && s[j] == ' ') j --;
if(i > j) return false;
s = s.substr(i, j - i + 1);
if(s[0] == '+' || s[0] == '-') s = s.substr(1); //从下标1开始一直到字符串结束
if(s.empty() || (s[0] == '.' && s.size() == 1)) return false; // +, . , -
int dot = 0, e = 0;
for(int i = 0; i < s.size(); i ++)
{
if(s[i] >= '0' && s[i] <= '9') ;//是数字
else if(s[i] == '.')
{
dot ++;
if(dot > 1 || e) return false; //12.12.12, 112e.121
}
else if(s[i] == 'e' || s[i] == 'E')
{
e ++;
if(!i || i + 1 == s.size() || e > 1 || s[i - 1] == '.' && i == 1) return false; //e125, 123e, .e1
if(s[i + 1] == '+' || s[i + 1] == '-')
{
if(i + 2 == s.size()) return false; //122e+
i ++;
}
}
else return false;
}
return true;
}
};
32. 调整数组顺序使奇数位于偶数前面
输入一个整数数组,实现一个函数来调整该数组中数字的顺序。
使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分。
样例
输入:[1,2,3,4,5]
输出: [1,3,5,2,4]
class Solution {
public:
void reOrderArray(vector<int> &array) {
int i = 0, j = array.size() - 1;
while(i <= j)
{
while(i <= j && array[i] % 2 == 1) i ++;// 奇数
while(i <= j && array[j] % 2 == 0) j --; //偶数
if(i < j) swap(array[i], array[j]); //没有相遇就交换
}
}
};
33. 链表中倒数第k个节点
输入一个链表,输出该链表中倒数第k个结点。
注意:
k >= 0;
如果k大于链表长度,则返回 NULL;
样例
输入:链表:1->2->3->4->5 ,k=2
输出:4
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* findKthToTail(ListNode* pListHead, int k) {
int n = 0;
for(auto p = pListHead; p; p = p->next) n ++;
if(k > n) return nullptr;
auto p = pListHead;
for(int i = 0; i < n - k; i ++) p = p->next;
return p;
}
};
34. 链表中环的入口结点
给定一个链表,若其中包含环,则输出环的入口节点。
若其中不包含环,则输出null。
样例
给定如上所示的链表:
[1, 2, 3, 4, 5, 6]
2
注意,这里的2表示编号是2的节点,节点编号从0开始。所以编号是2的节点就是val等于3的节点。
则输出环的入口节点3.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *entryNodeOfLoop(ListNode *head) {
auto i = head, j = head;
while(i && j)
{
i = i->next;
j = j->next;
if(j) j = j->next;
if(i == j) //第一次相遇 i回到起点
{
i = head;
while(i != j)
{
i = i->next;
j = j->next;
}
return i;
}
}
return 0;
}
};