一、旋转数组
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入:[1,2,3,4,5,6,7]
和 k = 3 输出:[5,6,7,1,2,3,4]
解释: 向右旋转 1 步:[7,1,2,3,4,5,6]
向右旋转 2 步:[6,7,1,2,3,4,5]
向右旋转 3 步:[5,6,7,1,2,3,4]
示例 2:
输入: [-1,-100,3,99]
和 k = 2
输出: [3,99,-1,-100]
解释:
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]
说明:
- 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
- 要求使用空间复杂度为 O(1) 的原地算法。
第一次代码:没有实现原地算法!时间复杂度过大
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int len=nums.size();
if(nums.empty()||k%len==0) return;
if(k>len) k=k%len;
vector<int> str;
while(k>0)
{
if(k>len) num=k%len;
for(int i=0;i<num;i++)
{
str[i]==nums[len-num];
num--;
}
for(int i=k;i<len-k;i++)
{
str[i]==nums[j];
j++;
k--;
}
}
}
};
第二次代码:
思路:
1.排除特殊情况:当nums==0或者k%len==0(不用旋转)
2.当k>len,不需要重复旋转,只需要旋转k%len次;
此处需用到倒置函数reverse()函数:可以对字符串进行反转操作,头文件是#include<algorithm>
容器类型的要用begin()和end()来指定反转的区域,数组类型的直接用int类型即可
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int len=nums.size();
if(nums.empty()||k%len==0) return;//特殊情况直接排除
if(k>len) k=k%len;
reverse(nums.begin(),nums.begin()+len-k);
reverse(nums.begin()+len-k,nums.end());
reverse(nums.begin(),nums.end());
}
};
第三次代码:
思路:利用STL的push_back()、erase()函数,每次从数组的开头取出数字插入到nums的末尾,再将开头擦去;
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int len=nums.size();
if(nums.empty()||k%len==0) return;
if(k>len) k=k%len;
for(int i=0;i<len-k;i++)
{
nums.push_back(nums[0]);
nums.erase(nums.begin());
}
}
};
二、杨辉三角 II
给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。
在杨辉三角中,每个数是它左上方和右上方的数的和。
示例:
输入: 3
输出: [1,3,3,1]
进阶:
你可以优化你的算法到 O(k) 空间复杂度吗?
思路:
1.和之前的杨辉三角I一样,把所有的计算出来,然后输出第n行,但效率不高;
2.利用两个for循环,除了第一个数为1,后面的数都是上一次循环的数值加上他前面位置的数值之和,不停的更新每一个位置的值,便可以得到第n行,效率较高。
例如:
rowIndex=4 ,输出结果应为 1 4 6 4 1
当i=1,res = 1 ,1
当i=2,res = 1 ,2 ,1
当i=3,res = 1 , 3, 3,1
当i=4,res = 1 , 4, 6, 4, 1
代码:
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<int> res(rowIndex + 1);//需要开辟n+1个大小,因为第n行有n+1个数字
res[0] = 1;
for(int i = 1; i <= rowIndex; ++i){//i必须<=rowIndex,i控制总体循环次数
for(int j = i ;j >= 1;--j){//j控制累加循环,从倒数第一个数每次计算完--,直到正向的第二个数(第一个1不需要计算)
res[j] += res[j-1];
}
}
return res;
}
};
注:
1.需要开辟n+1个大小,因为第n行有n+1个数字;
2.i必须<=rowIndex,i控制总体循环次数;
3.j控制累加循环,从倒数第一个数每次计算完--,直到正向的第二个数(第一个1不需要计算)
三、翻转字符串里的单词
给定一个字符串,逐个翻转字符串中的每个单词。
示例 1:
输入: "the sky is blue"
输出: "blue is sky the"
示例 2:
输入: " hello world! "
输出: "world! hello"
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:
输入: "a good example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
说明:
- 无空格字符构成一个单词。
- 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
- 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
进阶:
请选用 C 语言的用户尝试使用 O(1) 额外空间复杂度的原地解法。
思路:
1.传统方法:先整体翻转一次,然后再翻转每个单词;
2.利用栈先进后出的特点,从头遍历,每次遇到一个空格,则空格前的字符是一个单词,将单词存入到栈里面,全部压入栈后,每次将栈顶出栈,如果栈中还有单词,则将栈顶后连接一个空格,如果是最后一个单词的时候,不需要加空格,直接连接到末尾就可以。
注:这个方法直接不需要考虑源字符串中空格的个数,以及翻转后收尾是否有多余空格
代码:(思路2)
class Solution {
public:
string reverseWords(string s) {
stack<string> st;
string t,ans;
for (int i = 0; i < s.size(); ++i){//将每一个单词压栈
if (s[i] != ' '){
while (s[i] != ' ' && i < s.size()){
t += s[i];
++i;
}
st.push(t);
t.clear();
}
}
while (!st.empty()){
string tmp = st.top();
st.pop();
if (tmp != " "){
if (st.empty())//判断是否为栈中的最后一个单词
ans += tmp;
else
ans += tmp + ' ';
}
}
return ans;
}
};