目录
剑指 Offer 14- II. 剪绳子 II
方法一:
按照老思路解法:剑指 Offer 14- I. 剪绳子,发现溢出。
代码:
class Solution {
public:
int cuttingRope(int n) {
vector<long long> dp(n + 1, 0);
long long mod = 1e9 + 7;
dp[2] = 1;
for(int i = 3; i <= n; i++) {
for(int j = 1; j <= i - 2; j++) {
dp[i] = max(dp[i], max((long long)j * (i - j), dp[i - j] * j));
dp[i] = dp[i] % mod;
}
}
return dp[n];
}
};
方法二:
参考官方题解,核心思路是:尽可能把绳子分成长度为3的小段,这样乘积最大,证明略。
代码:
class Solution {
public:
int cuttingRope(int n) {
if(n < 4) {
return n - 1;
}
long long mod = 1e9 + 7;
int res = 1;
while(n > 4) {
res = (res % mod) * 3 % mod;
n -= 3;
}
res = (res % mod) * n % mod;
return res;
}
};
剑指 Offer 20. 表示数值的字符串
分析:
模拟,参考官方题解。
代码:
class Solution {
public:
bool scan_integer(string &s, int &i) {
int temp = i;
if(i < s.size() && (s[i] == '+' || s[i] == '-'))
++i;
return scan_unsigned_integer(s, i);
}
bool scan_unsigned_integer(string &s, int &i) {
int temp = i;
while(i < s.size() && isdigit(s[i]))
++i;
return i > temp;
}
bool isNumber(string s) {
//指针,记录扫描到s的哪个字符了
int i = 0;
//跳过初始的空格
for(; i < s.size(); ++i)
if(s[i] != ' ')
break;
//先判断打头的字符是不是一个有符号整数
bool flag = scan_integer(s, i);
//如果有小数点
if(s[i] == '.') {
++i;
//小数点的前后至少有一个整数
//注意:这里要先判断小数点后是否有无符号整数!!!
flag = scan_unsigned_integer(s, i) || flag;
}
//如果有e
if(s[i] == 'e' || s[i] == 'E') {
++i;
//e后面必须存在有符号整数
flag = flag && scan_integer(s, i);
}
//最后必须以空格收尾
for(; i < s.size(); ++i) {
if(s[i] != ' ') {
flag = false;
break;
}
}
return flag;
}
};
剑指 Offer 37. 序列化二叉树
分析:
层次遍历建树。
代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Codec {
public:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
string str = "";
//层次遍历
if(!root) {
return "";
}
queue<TreeNode*> que;
que.push(root);
while(!que.empty()) {
TreeNode* fr = que.front();
que.pop();
if(fr) {
str += to_string(fr->val);
str += ",";
que.push(fr->left);
que.push(fr->right); //这里不需要判断是否为NULL
}else {
str += "NULL,";
}
}
return str;
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
vector<string> res;
//拆分
if(data == "") {
return NULL;
}
int n = data.size();
//cout << data;
for(int i = 0; i < n; i++) {
int j = i;
while(data[j] != ',') {
j++;
}
string temp = data.substr(i, j - i);
if(temp == "NULL") {
res.push_back("NULL");
}else {
res.push_back(data.substr(i, j - i));
}
i = j;
}
//建树
TreeNode* root = new TreeNode(atoi(res[0].c_str()));
int ind = 1;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()) {
TreeNode* fr = que.front();
que.pop();
//左子树
if(res[ind] == "NULL") {
fr->left = NULL;
}else {
fr->left = new TreeNode(atoi(res[ind].c_str()));
que.push(fr->left);
}
ind++;
//右子树
if(res[ind] == "NULL") {
fr->right = NULL;
}else {
fr->right = new TreeNode(atoi(res[ind].c_str()));
que.push(fr->right);
}
ind++;
}
return root;
}
};
// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));
剑指 Offer 59 - II. 队列的最大值
方法一:
暴力求解。
代码:
class MaxQueue {
public:
queue<int> que;
vector<int> res;
MaxQueue() {
}
int max_value() {
if(que.empty()) {
return -1;
}
return *max_element(res.begin(), res.end());
}
void push_back(int value) {
que.push(value);
res.push_back(value);
}
int pop_front() {
if(que.empty()) {
return -1;
}
int t = que.front();
que.pop();
res.erase(res.begin());
return t;
}
};
/**
* Your MaxQueue object will be instantiated and called as such:
* MaxQueue* obj = new MaxQueue();
* int param_1 = obj->max_value();
* obj->push_back(value);
* int param_3 = obj->pop_front();
*/
方法二:
双端队列。
代码:
class MaxQueue {
queue<int> q;
deque<int> d;
public:
MaxQueue() {
}
int max_value() {
if (d.empty())
return -1;
return d.front();
}
void push_back(int value) {
while (!d.empty() && d.back() < value) {
d.pop_back();
}
d.push_back(value);
q.push(value);
}
int pop_front() {
if (q.empty())
return -1;
int ans = q.front();
if (ans == d.front()) {
d.pop_front();
}
q.pop();
return ans;
}
};
剑指 Offer 60. n个骰子的点数
分析:
动态规划,参考官方题解。
代码:
class Solution {
public:
vector<double> dicesProbability(int n) {
vector<vector<double>> dp(n + 1, vector<double>(n + 5 * n + 1, .0));
for(int j = 1; j <= 6; j++) {
dp[1][j] = 1.0/6;
}
for(int i = 2; i <= n; i++) {
for(int j = i; j < i + 5 * i + 1; j++) {
double res = 0;
for(int k = 1; k <= 6; k++) {
if(j - k < 0) {
continue;
}
res += dp[i - 1][j - k] / 6;
}
dp[i][j] = res;
}
}
return vector<double>(dp[n].begin() + n, dp[n].end());
}
};
剑指 Offer 67. 把字符串转换成整数
分析:
模拟。
代码:
class Solution {
public:
int strToInt(string str) {
int i = 0;
//1. 过滤掉前置空格,直到不为空格的字符。
while(i < str.size() && str[i] == ' '){
++i;
}
if(i>=str.size()){
return 0;
}
bool sign=false;
//提取+,-符号。
if(str[i] == '-'){
sign=true;
++i;
}else if(str[i] == '+'){
++i;
}
//
if(i >= str.size()){
return 0;
}
if(!isdigit(str[i])){
return 0;
}
long long ans = 0;
//提取整数部分。累加过程中,如果正数 > INT_MAX时,返回INT_MAX. 如果负数 < INT_MIN时,返回INT_MIN.
while(i < str.size() && isdigit(str[i])){
ans = ans*10 +(str[i] - '0');
if(!sign && ans > INT_MAX){
return INT_MAX;
}else if(sign && -ans < INT_MIN){
return INT_MIN;
}
++i;
}
return sign ? -ans : ans;
}
};
剑指 Offer 33. 二叉搜索树的后序遍历序列
分析:
递归。
代码:
class Solution {
public:
bool verifyPostorder(vector<int>& postorder) {
const int n = postorder.size();
return recur(postorder,0,n-1);
}
bool recur(vector<int>& postorder,int l,int r) {
if(l >= r) {
return true;
}
int i = l;
while(i < r && postorder[i] < postorder[r]) ++i;//找到右子树序列的第一个
if(i == r) {
return recur(postorder,l,r-1); //没有右子树序列,对应的数是只有左子树的单支树,递归考虑左子树
}
int tmp = i;//存储找到的右子树序列的第一个位置
while(i < r && postorder[i] > postorder[r]) ++i;//判断右子树序列的元素是否都比根节点大
if(i < r) return false;
return recur(postorder,l,tmp-1) && recur(postorder,tmp, r-1);//递归考虑左子树和右子树
}
};