- 最大交换
给定一个非负整数,你至多可以交换一次数字中的任意两位。返回你能得到的最大值。
先从低位往高位遍历,保存每一位经过交换能得到的最大值的下标
再从高位往低位遍历,直到某一位小于该位可以取到的最大值,上一步保存了该位置最大值的下标,交换即可
class Solution {
public:
int maximumSwap(int num) {
string str = to_string(num);
int n = str.size();
vector<int> res(n, n);
int index = n, maxnum = -1;
for (int i = n - 1; i >= 0; i--) {
if (str[i] - '0' > maxnum) {
maxnum = str[i] - '0';
index = i;
}
else if (str[i] - '0' < maxnum){
res[i] = index;
}
}
for (int i = 0; i < n; i++) {
if (res[i] != n) {
swap(str[i], str[res[i]]);
break;
}
}
return stoi(str);
}
};
- 二叉树中第二小的节点
给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么该节点的值等于两个子节点中较小的一个。
更正式地说,root.val = min(root.left.val, root.right.val) 总成立。
给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。
1、 首先根据题目根节点的值一定是最小的值。
2、 根据题目给出的节点条件,可得出以下信息(结合图理解):
a) 第二小的值一定出现在与根节点值相同节点的左右子树上。
b) 根节点的值一定会延伸到至少一个叶子结点,否则就不满足当前节点始终等于左右节点的较小值。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int findSecondMinimumValue(TreeNode* root) {
//如果当前节点无左右节点,因为当前节点值一定与根节点值相同,所有没有更大的节点值,返回-1
if(root->left == nullptr && root->right == nullptr)
return -1;
int lval = -1,rval = -1;
//如果左边的节点的值等于根节点的值,则我们需要递归去寻找左子树上大于根节点值的节点值
if(root->left->val == root->val){
lval = findSecondMinimumValue(root->left);
}else{
//否则直接取出大于根节点值的节点值
lval = root->left->val;
}
//右边同理
if(root->right->val == root->val){
rval = findSecondMinimumValue(root->right);
}else{
rval = root->right->val;
}
//只要有一个为-1,则返回另一个,否则返回左右的较小值
if(lval == -1)
return rval;
if(rval == -1)
return lval;
return min(rval,lval);
}
};
- 灯泡开关2
现有一个房间,墙上挂有 n 只已经打开的灯泡和 4 个按钮。在进行了 m 次未知操作后,你需要返回这 n 只灯泡可能有多少种不同的状态。
实际是一道脑筋急转弯,变化的数量是有限的,穷举即可
class Solution {
public:
int flipLights(int n, int m) {
if(n ==0 || m == 0){
return 1;
}
if(n == 1){
return 2;
}
else if(n == 2 && m == 1){
return 3;
}
else if((n == 2 && m >= 2) || m == 1){
// n < 3的情况已被前面的if排除
// 因此当n>=3时,只需判断m==1即可
return 4;
}
else if(n >= 3 && m == 2){
return 7;
}
else {
return 8;
}
}
};
- 最长递增子序列的个数
给定一个未排序的整数数组,找到最长递增子序列的个数。
采用动态规划存取以i结尾的数组最长递增子序列长度,如果以j结尾的最大长度和i一样,则总数加1,否则更新新长度。
class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
int n = nums.size();
if(n<=0) return n;
vector<int> dp(n, 1);
vector<int> count(n,1);
for(int i=1; i<n; i++) {
for(int j=0; j<i; j++) {
if(nums[j] < nums[i]) {
// 第一次找到
if(dp[j]+1 > dp[i]) {
dp[i] = dp[j] + 1;
count[i] = count[j];
// 再次找到
} else if(dp[j]+1 == dp[i]) {
count[i] += count[j];
}
}
}
}
// 最后的返回值应该是所有最大长度的所有count的总和
int max = *max_element(dp.begin(), dp.end());
int res = 0;
for(int i=0; i<n; i++) {
if(dp[i] == max)
res += count[i];
}
return res;
}
};
- 最长连续递增序列
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
主要思路就是贪心法取最长串,因为如果想最长,那一定得从头开始,如果中间有一个不满足,那只能重新算。
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
int ans = 0;
int n = nums.size();
int start = 0;
for (int i = 0; i < n; i++) {
if (i > 0 && nums[i] <= nums[i - 1])
{
start = i;
}
else
{
ans = max(ans, i - start + 1);
}
}
return ans;
}
};
- 为高尔夫比赛砍树
你被请来给一个要举办高尔夫比赛的树林砍树。树林由一个 m x n 的矩阵表示,你需要按照树的高度从低向高砍掉所有的树,每砍过一颗树,该单元格的值变为 1(即变为地面)。你将从 (0, 0) 点开始工作,返回你砍完所有树需要走的最小步数。 如果你无法砍完所有的树,返回 -1 。可以保证的是,没有两棵树的高度是相同的,并且你至少需要砍倒一棵树。
在BFS基础上进行一些优化
int f[3050], vis[3050], sz, m,n,n2;
int q[3050], st[3050];
int tr[3000], cnt;
class Solution {
public:
int cutOffTree(vector<vector<int>>& forest) {
sz = 0, m = forest.size(), n = forest[0].size(),n2 = n+2, cnt = 0;
// 数据预处理
for(int i = 0; i < n2; ++i) f[sz++] = 0;
tr[cnt++] = sz+1; // 我们需要从 [0,0] 开始
for(int i = 0; i < forest.size(); ++i) {
f[sz++] = 0;
for(int j = 0; j < forest[0].size(); ++j, ++sz) {
f[sz] = forest[i][j];
if(f[sz] > 1) tr[cnt++] = sz;
}
f[sz++] = 0;
}
for(int i = 0; i < n2; ++i) f[sz++] = 0;
memset(vis, 0, sz*sizeof(int));
// 按树的高度从低向高排序
sort(tr + 1, tr + cnt, [](int &a, int &b) {
return f[a] < f[b];
});
// 间隔 bfs
int res = 0, t[2];
for(int i = (tr[0] == tr[1]? 2 : 1); i < cnt; i += 2) {
t[0] = tr[i-1], t[1] = ((i + 1 == cnt)? -1 : tr[i+1]);
if(!bfs(i, tr[i], t, 1 + (t[1] != -1), res))
return -1;
}
return res;
}
bool bfs(int num, int s, int t[], int obj, int& res) {
int got = 0, go[4] = {
1,-1,n2,-n2};
q[0] = s, st[0] = 0, vis[s] = num;
for(int r = 0, w = 1; r != w; ++r)
for(int d = 0; d < 4; ++d) {
int ne = q[r] + go[d];
if(f[ne] && vis[ne] != num) {
if(ne == t[0]) res += st[r] + 1, ++got;
if(ne == t[1]) res += st[r] + 1, ++got;
if(got == obj) return true;
vis[ne] = num, q[w] = ne, st[w] = st[r] + 1,++w;
}
}
return false;
}
};
- 实现一个魔法字典
class MagicDictionary {
public:
/** Initialize your data structure here. */
unordered_map<string, vector<string>> container;
MagicDictionary() {
}
void buildDict(vector<string> dictionary) {
for (auto e : dictionary) {
auto proto = e;
for (int i = 0; i < e.size(); ++i) {
char c = e[i];
e[i] = '_';
container[e].emplace_back(proto);
e[i] = c;
}
}
}
bool search(string searchWord) {
auto e = searchWord;
for (int i = 0; i < searchWord.size(); ++i) {
char c = searchWord[i];
searchWord[i] = '_';
if (container.find(searchWord) != container.end() && (container[searchWord].size() > 1 || container[searchWord][0] != e)) return true;
searchWord[i] = c;
}
return false;
}
};
/**
* Your MagicDictionary object will be instantiated and called as such:
* MagicDictionary* obj = new MagicDictionary();
* obj->buildDict(dictionary);
* bool param_2 = obj->search(searchWord);
*/
/**
* Your MagicDictionary object will be instantiated and called as such:
* MagicDictionary* obj = new MagicDictionary();
* obj->buildDict(dictionary);
* bool param_2 = obj->search(searchWord);
*/