419甲板上的战舰
只要统计战舰头的个数即可,每个战舰头的左边和上面一定是 ‘ . ’ ,只要判断这个条件,把所有的战舰头统计一下就行了
一次扫描并且额外空间O(1)
class Solution {
public:
int countBattleships(vector<vector<char>>& board) {
int count = 0;
for(int i = 0; i < board.size(); i++){
for(int j = 0; j < board[0].size(); j++){
if(board[i][j] == 'X' && (i == 0 || board[i - 1][j] == '.')
&& (j == 0 || board[i][j - 1] == '.')){
count ++;
}
}
}
return count;
}
};
看了题解好像没有比这个更优的解法了,就没重新改进了-_-
189旋转数组
自己马上想到的就是直接另外开一个数组,然后一个一个赋值
时间和空间复杂度都是O(N)
class Solution {
public:
void rotate(vector<int>& nums, int k) {
vector<int> res = nums;
for(int i = 0; i < nums.size(); i++){
nums[(i + k) % nums.size()] = res[i];
}
}
};
要求用三种方法…
然后看了题解
数组翻转
当我们将数组的元素向右移动 k 次后,尾部 k mod n 个元素会移动至数组头部,其余元素向后移动。
该方法为数组的翻转:
- 我们可以先将所有元素翻转,这样尾部的 k mod n个元素就被移至数组头部
- 然后我们再翻转 [0, k mod n -1][0,kmodn−1] 区间的元素
- 翻转 [k mod n, n-1][k mod n,n−1] 区间的元素即能得到最后的答案。
class Solution {
public:
void reverse(vector<int>& nums, int start, int end){
while(start < end){
swap(nums[start], nums[end]);
start ++;
end --;
}
}
void rotate(vector<int>& nums, int k) {
k = k % nums.size();//因为没有说k会小于nums.size()
reverse(nums, 0, nums.size() - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, nums.size() - 1);
}
};
这种方法所有的元素都被遍历到两次,O(2N) = O(N),
空间复杂度O(1)
3 环形旋转
要注意如果nums.size()刚好是k的整数倍的话,会出现死循环,因此可以另外设置一个visit数组,如果已经访问过,就往后移动一位继续替换,但是这种情况还是要另外开一个n的数组,还不如直接用第一种做法简单直接
环状替换
这是最优的解法(目前),只要遍历一次数组,并且没有额外的空间开销
上一种做法是每次cur和next移动,把移动后的互相替换,但是这个是每次都是用i位置的替换,直到下一次替换到i,完成一轮,总共需要n和k的最大公约数轮
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = nums.size();
k = k % n;
int count = gcd(n, k);//最大公约数
for(int i = 0; i < count; i++){
int cur = i;
int first = nums[i];
do{
int next = (cur + k) % n;
swap(first, nums[next]);
cur = next;
}while(i != cur);
}
}
};
这些用户是魔鬼吗??