前言
C语言刷题太麻烦了,尤其是后面的哈希表之类的,所以我又学习了一些C++的东西,做了一些C++的解答。
1.1 数组基础理论
(1)定义:数组是存储在连续内存空间上相同类型数据的集合。
(2)注意:
- 数组下标是从0开始的;
- 数组在内存空间的地址是连续的。
=>删除或增添数组元素难免要移动其他元素的地址
(3)数组中的元素不能删除,只能覆盖
1.2 二分查找
1.2.1 二分法介绍
(1)使用前提:数组元素是有序的。
(2)时间复杂度:O (log N)
(3)二分法的区间定义有两种:左闭右闭 [left, right] 和 左闭右开 [left, right)
- 左闭右闭 [left, right]
前提边界条件设置:
int left = 0;
int right = numsSize - 1; //尤其注意这里
补充:在求中点 mid 时,用位运算更好一点
int mid = left + ((right - left) >> 1);
有两点要注意:
while (left <= right) // 注意这里是 <=
if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid + 1; // 注意这里有 + 1
else
return mid;
- 左闭右开 [left, right)
前提边界条件设置:
int left = 0;
int right = numsSize; // 注意这里没有进行 - 1
有两点要注意:
while (left < right) // 注意这里只是 <
if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid; // 注意这里没有进行 + 1
else
return mid;
1.2.2 相关题目推荐
704、二分查找
- 左闭右闭
int search(int* nums, int numsSize, int target){
int left = 0, right = numsSize - 1;
int middle;
// 用的左闭右闭[left, right]
while (left <= right) {
middle = left + ((right - left) >> 1);
if (nums[middle] > target) {
// 注意这里
right = middle - 1;
}else if (nums[middle] < target) {
left = middle + 1;
}else {
return middle;
}
}
return -1;
}
(cpp)
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int mid = 0;
while (left <= right) {
mid = left + ((right - left) >> 1);
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else {
return mid;
}
}
return -1;
}
};
- 左闭右开
int search(int* nums, int numsSize, int target){
int left = 0, right = numsSize; //注意这里没有 减一
int middle = 0;
// 左闭右开 [left, right)
while (left < right) {
middle = left + ((right - left) >> 1);
if (nums[middle] > target) {
// 注意这里
right = middle;
}else if (nums[middle] < target) {
left = middle + 1;
}else {
return middle;
}
}
return -1;
}
cpp
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size();
int mid = 0;
while (left < right) {
mid = left + ((right - left) >> 1);
if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid;
else
return mid;
}
return -1;
}
};
35、搜索插入位置
- 暴力解法
int searchInsert(int* nums, int numsSize, int target){
// 暴力解法
for (int i = 0; i < numsSize; i++) {
if (nums[i] >= target) {
return i;
}
}
return numsSize;
}
- 二分法:左闭右闭
int searchInsert(int* nums, int numsSize, int target){
// 二分法
int left = 0, right = numsSize - 1;
int middle = 0;
// 左闭右闭 [left, right]
while (left <= right) {
middle = left + ((right - left) >> 1);
if (nums[middle] > target) {
right = middle - 1;
}else if (nums[middle] < target) {
left = middle + 1;
}else {
return middle;
}
}
// 注意这里,如果target没在数组里面,是返回的right + 1
return right + 1;
}
注意:这里返回 left 也是可以的
cpp
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int mid = 0;
while (left <= right) {
mid = left + ((right - left) >> 1);
if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid - 1;
else
return mid;
}
return left;
}
};
- 二分法:左闭右开
int searchInsert(int* nums, int numsSize, int target){
// 二分法
int left = 0, right = numsSize; // 注意这里没有减一
int middle = 0;
// 左闭右开
while (left < right) {
middle = left + ((right - left) >> 1);
if (nums[middle] > target) {
right = middle;
}else if (nums[middle] < target) {
left = middle + 1;
}else {
return middle;
}
}
// 注意这里返回的是 right
return right;
}
注意:这里返回 left 也是可以的
cpp
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0;
int right = nums.size();
int mid = 0;
while (left < right) {
mid = left + ((right - left) >> 1);
if (nums[mid] < target)
left = left + 1;
else if (nums[mid] > target)
right = mid;
else
return mid;
}
return right;
}
};
34、在排序数组中查找元素的第一个和最后一个位置
LeetCode:34.在排序数组中查找元素的第一个和最后一个位置
- 暴力求解
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* searchRange(int* nums, int numsSize, int target, int* returnSize){
int i;
int flag = 1;
int *ret = (int *)malloc(sizeof(int) * 2);
ret[0] = -1;
ret[1] = -1;
for (i = 0; i < numsSize; i++) {
if (nums[i] == target && flag == 1) {
ret[0] = i;
flag = 0;
}
if (nums[i] == target && flag == 0) {
ret[1] = i;
}
}
*returnSize = 2;
return ret;
}
- 二分法:分别找出左右边界
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int getRightBorder(int *nums, int numsSize, int target) {
int left = 0, right = numsSize - 1;
int middle = 0;
int rightBorder = -1;
while (left <= right) {
middle = left + ((right - left) >> 1);
if (nums[middle] == target) {
rightBorder = middle;
}
if (nums[middle] > target) {
right = middle - 1;
}else {
left = middle + 1;
}
}
return rightBorder;
}
int getLeftBorder(int *nums, int numsSize, int target) {
int left = 0, right = numsSize - 1;
int middle = 0;
int leftBorder = -1;
while (left <= right) {
middle = left + ((right - left) >> 1);
if (nums[middle] == target) {
leftBorder = middle;
}
if (nums[middle] < target) {
left = middle + 1;
}else {
right = middle - 1;
}
}
return leftBorder;
}
int* searchRange(int* nums, int numsSize, int target, int* returnSize){
int *ret = (int *)malloc(sizeof(int) * 2);
int rightBorder = getRightBorder(nums, numsSize, target);
int leftBorder = getLeftBorder(nums, numsSize, target);
if (rightBorder == -1 || leftBorder == -1) {
ret[0] = -1;
ret[1] = -1;
}else {
ret[0] = leftBorder;
ret[1] = rightBorder;
}
*returnSize = 2;
return ret;
}
cpp
class Solution {
public:
int getLeftBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int mid = 0;
int leftBorder = -1;
while (left <= right) {
mid = left + ((right - left) >> 1);
if (nums[mid] == target)
leftBorder = mid;
if (nums[mid] < target)
left = mid + 1;
else
right = mid - 1;
}
return leftBorder;
}
int getRightBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int mid = 0;
int rightBorder = -1;
while (left <= right) {
mid = left + ((right - left) >> 1);
if (nums[mid] == target){
rightBorder = mid;
}
if (nums[mid] > target){
right = mid - 1;;
} else {
left = mid + 1;
}
}
return rightBorder;
}
vector<int> searchRange(vector<int>& nums, int target) {
int leftBorder = getLeftBorder(nums, target);
int rightBorder = getRightBorder(nums, target);
if (leftBorder != -1 && rightBorder != -1)
return vector<int> {leftBorder, rightBorder};
else
return vector<int> {-1, -1};
}
};
69、x的平方根
- 暴力求解
int mySqrt(int x){
// 暴力求解
int factor = 0;
for (int i = 0; i <= x; i++) {
if ((double)i * i <= x) {
factor = i;
}else {
return factor;
}
}
return x;
}
- 二分法
int mySqrt(int x){
int left = 0, right = x;
int middle = 0;
long temp = 0;
int factor = 0;
while (left <= right) {
middle = left + ((right - left) >> 1);
temp = (long)middle *middle;
if (temp <= x) {
factor = middle;
left = middle + 1;
}else {
right = middle -1;
}
}
return factor;
}
cpp
class Solution {
public:
int mySqrt(int x) {
if (0 == x || 1 == x) {
return x;
}
int left = 1;
int right = x / 2;
int mid = 0;
long temp = 0.0;
int factor = 0;
while (left <= right) {
mid = left + ((right - left) >> 1);
temp = (long)mid * mid;
if (temp <= x) {
factor = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return factor;
}
};
367、有效的完全平方数
- 暴力求解
bool isPerfectSquare(int num){
// 暴力解法
int i;
for (i = 1; i <= (num / 2 + 1); i++) {
if ((long)i * i == num) {
return true;
}
}
return false;
}
- 二分法
bool isPerfectSquare(int num){
// 二分法
int left = 0, right = num;
int middle = 0;
while (left <= right) {
middle = left + ((right - left) >> 1);
if ((long)middle * middle == num) {
return true;
}else if ((long)middle * middle > num){
right = middle - 1;
}else {
left = middle + 1;
}
}
return false;
}
cpp
class Solution {
public:
bool isPerfectSquare(int num) {
if (1 == num) {
return true;
}
int left = 1;
int right = num / 2;
int mid = 0;
long temp = 0;
while (left <= right) {
mid = left + ((right - left) >> 1);
temp = (long)mid * mid;
if (temp < num) {
left = mid + 1;
} else if (temp > num) {
right = mid - 1;
} else {
return true;
}
}
return false;
}
};
1.3 移除元素(双指针法)
1.3.1 双指针法介绍
- 数组元素无法真正移除,只能靠后一个元素覆盖前一个元素,返回移除后的数组没有意义。
- 双指针法(快慢指针法):通过一个快指针和慢指针在一个for循环内完成两个for循环的工作。
快指针:寻找新数组的元素,新数组就是不含目标元素的数组。
慢指针:指向更新新数组下标的位置。
1.3.2 相关题目推荐
27、移除元素
- 暴力解法
int removeElement(int* nums, int numsSize, int val){
// 暴力解法 两个for循环
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
int size = numsSize;
for (int i = 0; i < size; i++) {
if (nums[i] == val) { //发现需要移动的元素,就将数组整体向前移动一位
for (int j = i + 1; j < size; j++) {
nums[j - 1] = nums[j];
}
i--; // 因为i下标以后的元素都向前移动了一位,所以i也向前移动一位
size--; // 此时数组的大小 -1
}
}
return size;
}
- 双指针法
int removeElement(int* nums, int numsSize, int val){
// 通用解法
// 世界复杂度:O(n)
// 空间复杂度:O(1)
int count = 0;
for (int i = 0; i < numsSize; i++) {
if (nums[i] != val) {
nums[count++] = nums[i];
}
}
return count;
}
cpp
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int count = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] != val) {
nums[count++] = nums[i];
}
}
return count;
}
};
- 双向双指针
int removeElement(int* nums, int numsSize, int val){
/**
* 相向双指针方法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素
* 时间复杂度:O(n)
* 空间复杂度:O(1)
*/
int left_index = 0;
int right_index = numsSize - 1;
while (left_index <= right_index) {
// 找到左边等于val的元素
while (left_index <= right_index && nums[left_index] != val) {
left_index++;
}
// 找到右边不等于val地元素
while (left_index <= right_index && nums[right_index] == val) {
right_index--;
}
// 将右边不等于val的元素覆盖左边等于val的元素
if (left_index < right_index) {
nums[left_index++] = nums[right_index--];
}
}
return left_index; // leftIndex一定指向了最终数组末尾的下一个元素
}
cpp
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
while (left <= right && nums[left] != val) {
left++;
}
while (left <= right && nums[right] == val) {
right--;
}
if (left <= right) {
nums[left++] = nums[right--];
}
}
return left;
}
};
26、删除有序数组中的重复项
- 双指针法
(我写的版本)
int removeDuplicates(int* nums, int numsSize){
int slow = 0;
for (int i = 0; i < numsSize; i++) {
if (nums[i] != nums[slow]) {
nums[++slow] = nums[i];
}
}
return slow + 1;
}
参考版本
int removeDuplicates(int* nums, int numsSize){
// 双指针法
// 时间复杂度:O(n)
// 空间复杂度:O(1)
if (0 == numsSize) {
return 0;
}
int fast = 1, slow = 1;
while (fast <numsSize) {
if (nums[fast] != nums[fast - 1]) {
nums[slow++] = nums[fast];
}
fast++;
}
return slow;
}
cpp
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if (nums.size() == 1) {
return 1;
}
int slow = 1;
int fast = 1;
while (fast < nums.size()) {
if (nums[fast] != nums[fast - 1]) {
nums[slow++] = nums[fast];
}
fast++;
}
return slow;
}
};
283、移动零
- 双指针法(覆盖)
void moveZeroes(int* nums, int numsSize){
// 双指针法(快慢指针)
int slow = 0;
for (int fast = 0; fast < numsSize; fast++) {
if (nums[fast] != 0)
nums[slow++] = nums[fast];
}
// 将slow后面的元素全部赋值为0
while (slow < numsSize) {
nums[slow++] = 0;
}
}
cpp
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int count = 0;
int i = 0;
for (i = 0; i < nums.size(); i++) {
if (nums[i] != 0) {
nums[count++] = nums[i];
}
}
while (count < nums.size()) {
nums[count++] = 0;
}
}
};
- 双指针法(交换)
void moveZeroes(int* nums, int numsSize){
// 双指针法(交换)
// 时间复杂度:O(n)
// 空间复杂度:O(1)
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
// 左指针左边均为非零数
// 右指针左边直到左指针处均为零
int left = 0, right = 0;
while (right < numsSize) {
if (nums[right]) {
swap(nums + left, nums + right);
left++;
}
right++;
}
}
cpp
class Solution {
public:
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
void moveZeroes(vector<int>& nums) {
int left = 0;
int right = 0;
while (right < nums.size()) {
if (nums[right] != 0) {
swap(nums[left], nums[right]);
left++;
}
right++;
}
}
};
844、比较含退格的字符串(好难啊!)
- 双指针法
bool backspaceCompare(char * s, char * t){
int i = strlen(s) - 1;
int j = strlen(t) - 1;
int skip_s = 0;
int skip_t = 0;
while (i >= 0 || j >= 0) {
// 先找到 s 中第一个需要比较的字符(即去除 # 影响后的第一个待比较字符)
while (i >= 0) {
if (s[i] == '#') {
skip_s++;
i--;
}else if (skip_s > 0) {
skip_s--;
i--;
}else {
break;
}
}
// 再找到 t 中第一个需要比较的字符(即去除 # 影响后的第一个待比较字符)
while (j >= 0) {
if (t[j] == '#') {
skip_t++;
j--;
}else if (skip_t > 0) {
skip_t--;
j--;
}else {
break;
}
}
// 然后开始比较,注意有下面这个 if 条件的原因是:如果 index = 0 位置上为 '#',则 i, j 会为 -1
// 而 index = -1 的情况应当处理。
if (i >= 0 && j >= 0) {
// 如果待比较字符不同,return false
if (s[i] != t[j]) {
return false;
}
// (i >= 0 && j >= 0) 为 false 情况为
// 1. i < 0 && j >= 0
// 2. j < 0 && i >= 0
// 3. i < 0 && j < 0
// 其中,第 3 种情况为符合题意情况,因为这种情况下 s 和 t 都是 index = 0 的位置为 '#' 而这种情况下
// 退格空字符即为空字符,也符合题意,应当返回 True。
// 但是,情况 1 和 2 不符合题意,因为 s 和 t 其中一个是在 index >= 0 处找到了待比较字符,另一个没有找到
// 这种情况显然不符合题意,应当返回 False,下式便处理这种情况。
}else if (i >= 0 || j >= 0) {
return false;
}
i--;
j--;
}
return true;
}
cpp
class Solution {
public:
bool backspaceCompare(string s, string t) {
int i = s.length() - 1;
int j = t.length() - 1;
int flag_s = 0;
int flag_t = 0;
while (i >= 0 || j >= 0) {
while (i >= 0) {
if (s[i] == '#') {
flag_s++;
i--;
} else if (flag_s > 0) {
flag_s--;
i--;
} else {
break;
}
}
while (j >= 0) {
if (t[j] == '#') {
flag_t++;
j--;
} else if (flag_t > 0) {
flag_t--;
j--;
} else {
break;
}
}
if (i >= 0 && j >= 0) {
if (s[i] != t[j]) {
return false;
}
} else if (i >= 0 || j >= 0) {
return false;
}
i--;
j--;
}
return true;
}
};
- 重构字符串
char *build(char *string) {
int size = strlen(string);
int len = 0;
char *ret = (char *)malloc(sizeof(char) *(size + 1));
for (int i = 0; i < size; i++) {
if (string[i] != '#') {
ret[len++] = string[i];
}else if (len > 0) {
len--;
}
}
ret[len] = '\0';
return ret;
}
bool backspaceCompare(char * s, char * t){
// 重构字符串
// 时间复杂度:O(n)
// 空间复杂度:O(1)
return strcmp(build(s), build(t)) == 0;
}
cpp
class Solution {
public:
string getString(const string &S) {
string s;
for (int i = 0; i < S.size(); i++) {
if (S[i] != '#') {
s += S[i];
} else if (!s.empty()) {
s.pop_back();
}
}
return s;
}
bool backspaceCompare(string s, string t) {
return getString(s) == getString(t);
}
};
1.4 有序数组的平方(双指针法)
977、有序数组的平方
- 双指针法
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* sortedSquares(int* nums, int numsSize, int* returnSize){
// 双指针
// 时间复杂度:O(n)
// 空间复杂度:O(1)
int *arr = (int *)malloc(sizeof(int) * numsSize);
int left = 0;
int right = numsSize - 1;
int k = numsSize - 1;
while (left <= right) {
if (nums[left] *nums[left] <= nums[right] * nums[right]) {
arr[k--] = nums[right] *nums[right];
right--;
}else {
arr[k--] = nums[left] * nums[left];
left++;
}
}
*returnSize = numsSize;
return arr;
}
代码中平方对比可以转换一下:
while (left <= right) {
// 注意这一步的操作,没有直接比较平方
if (nums[left] + nums[right] <= 0) {
arr[k--] = nums[left] *nums[left];
left++;
}else {
arr[k--] = nums[right] * nums[right];
right--;
}
}
cpp
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> ret(nums.size(), 0);
int k = ret.size() - 1;
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
if (nums[left] + nums[right] < 0) {
ret[k--] = nums[left] * nums[left];
left++;
} else {
ret[k--] = nums[right] * nums[right];
right--;
}
}
return ret;
}
};
1.5 长度最小的子数组(滑动窗口法)
1.5.1 滑动窗口法介绍
- 滑动窗口法:不断调节子序列的起始位置和终止位置,从而得到想要的结果(也可以理解为双指针的一种)。
- 滑动窗口法三点注意:
(1)窗口内是什么?
(2)如何移动窗口的起始位置?
(3)如何移动窗口的结束位置?
1.5.2 相关题目推荐
209、长度最小的子数组
- 暴力解法(超出时间限制)
int minSubArrayLen(int target, int* nums, int numsSize){
int count = INT32_MAX;
int sum = 0;
int k = 0;
for (int i = 0; i < numsSize; i++) {
sum = 0;
for (int j = i; j < numsSize; j++) {
sum += nums[j];
if (sum >= target) {
k = j - i + 1;
count = count < k ? count : k;
break;
}
}
}
return count == INT32_MAX ? 0 : count;
}
- 滑动窗口法
int minSubArrayLen(int target, int* nums, int numsSize){
// 滑动窗口法
// 时间复杂度:O(n)
// 空间复杂度:O(1)
int count = INT32_MAX;
int sum = 0;
int left = 0; // left表示滑动窗口的起始位置,i表示滑动窗口的结束位置
for (int i = 0; i < numsSize; i++) {
sum += nums[i];
// 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
while (sum >= target) {
count = count < (i - left + 1) ? count : (i - left + 1);
// 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
sum -= nums[left++];
}
}
// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
return count == INT32_MAX ? 0 : count;
}
cpp
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int count = INT32_MAX;
int left = 0;
int right = 0;
int sum = 0;
while (right < nums.size()) {
sum += nums[right];
while (sum >= target) {
count = count < (right - left + 1) ? count : (right - left + 1);
sum -= nums[left++];
}
right++;
}
return count == INT32_MAX ? 0 : count;
}
};
904、水果成篮
- 滑动窗口法
#define MAX 100001
int totalFruit(int* fruits, int fruitsSize){
int count = 0, kind = 0;
int array[MAX] = {0}; //存放各种水果出现的次数
int left = 0, right = 0;
for (; right < fruitsSize; right++) {
if (array[fruits[right]] == 0) {
kind++;
}
array[fruits[right]]++;
while (kind > 2) {
array[fruits[left]]--;
if (array[fruits[left]] == 0) {
kind--;
}
left++;
}
count = count > (right - left + 1) ? count : (right - left + 1);
}
return count;
}
cpp
#define Max 100001
class Solution {
public:
int totalFruit(vector<int>& fruits) {
int n = fruits.size();
unordered_map<int, int> cnt;
int left = 0;
int count = 0;
for (int right = 0; right < n; right++) {
cnt[fruits[right]]++;
while (cnt.size() > 2) {
auto it = cnt.find(fruits[left]);
it->second--;
if (it->second == 0) {
cnt.erase(it);
}
left++;
}
count = max(count, right - left + 1);
}
return count;
}
};
1.6 螺旋矩阵(模拟行为法)
59、螺旋矩阵 II
- 方法一:只适合方阵
int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
//初始化返回的结果数组的大小
*returnSize = n;
*returnColumnSizes = (int*)malloc(sizeof(int) * n);
//初始化返回结果数组array
int **array = (int **)malloc(sizeof(int *) * n);
for (int i = 0; i < n; i++) {
array[i] = (int *)malloc(sizeof(int) * n);
(*returnColumnSizes)[i] = n;
}
// 设置每次循环的起始位置
int startx = 0, starty = 0;
// 添加的数字
int count = 1;
// 偏移数
int offset = 1;
// 循环的圈数
int circle = n/2;
int i, j;
while (circle--) {
// 模拟上侧从左到右
for (j = starty; j < n - offset; j++)
array[startx][j] = count++;
// 模拟右侧从上到下
for (i = startx; i < n - offset; i++)
array[i][j] = count++;
// 模拟下侧从右到左
for (; j > starty; j--)
array[i][j] = count++;
// 模拟左侧从下到上
for (; i > startx; i--) {
array[i][j] = count++;
}
// 遍历起始位置加一
startx++;
starty++;
// 位置偏移加一
offset++;
}
// 若n为奇数需要单独给矩阵中间赋值
if (n % 2)
array[n / 2][n / 2] = count;
return array;
}
- 方法二:适合任意矩阵
int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){
//初始化返回的结果数组的大小
*returnSize = n;
*returnColumnSizes = (int*)malloc(sizeof(int) * n);
//初始化返回结果数组array
int **array = (int **)malloc(sizeof(int *) * n);
for (int i = 0; i < n; i++) {
array[i] = (int *)malloc(sizeof(int) * n);
(*returnColumnSizes)[i] = n;
}
int x = 0, y = 0;
int x_max = n - 1, y_max = n - 1;
int count = 1;
int i, j;
while (1) {
for (j = y; j <= y_max; j++)
array[x][j] = count++;
if (++x > x_max) break;
for (i = x; i <= x_max; i++)
array[i][y_max] = count++;
if (--y_max < y) break;
for (j = y_max; j >= y; j--)
array[x_max][j] = count++;
if (--x_max < x) break;
for (i = x_max; i >= x; i--)
array[i][y] = count++;
if (++y > y_max) break;
}
return array;
}
cpp
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> ret(n, vector<int>(n));
int x = 0, y = 0;
int x_max = n - 1, y_max = n - 1;
int count = 1;
while (1) {
for (int j = y; j <= y_max; j++)
ret[x][j] = count++;
if (++x > x_max) break;
for (int i = x; i <= x_max; i++)
ret[i][y_max] = count++;
if (--y_max < y) break;
for (int j = y_max; j >= y; j--)
ret[x_max][j] = count++;
if (--x_max < x) break;
for (int i = x_max; i >= x; i--)
ret[i][y] = count++;
if (++y > y_max) break;
}
return ret;
}
};
54、 螺旋矩阵
int* spiralOrder(int** matrix, int matrixSize, int* matrixColSize, int* returnSize){
if (0 == matrixSize) {
*returnSize = 0;
return NULL;
}
int row = matrixSize, column = matrixColSize[0];
int size = row * column;
*returnSize = size;
int *array = malloc(sizeof(int) * size);
int x = 0, y = 0;
int x_max = row - 1, y_max = column - 1;
int count = 0;
int i, j;
while (1) {
for (j = y; j <= y_max; j++)
array[count++] = matrix[x][j];
if (++x > x_max) break;
for (i = x; i <= x_max; i++)
array[count++] = matrix[i][y_max];
if (--y_max < y) break;
for (j = y_max; j >= y; j--)
array[count++] = matrix[x_max][j];
if (--x_max < x) break;
for (i = x_max; i >= x; i--)
array[count++] = matrix[i][y];
if (++y > y_max) break;
}
return array;
}
剑指 Offer 29. 顺时针打印矩阵
int* spiralOrder(int** matrix, int matrixSize, int* matrixColSize, int* returnSize){
if (0 == matrixSize) {
*returnSize = 0;
return NULL;
}
int row = matrixSize, column = matrixColSize[0];
int size = row * column;
*returnSize = size;
int *array = malloc(sizeof(int) * size);
int x = 0, y = 0;
int x_max = row - 1, y_max = column - 1;
int count = 0;
int i, j;
while (1) {
for (j = y; j <= y_max; j++)
array[count++] = matrix[x][j];
if (++x > x_max) break;
for (i = x; i <= x_max; i++)
array[count++] = matrix[i][y_max];
if (--y_max < y) break;
for (j = y_max; j >= y; j--)
array[count++] = matrix[x_max][j];
if (--x_max < x) break;
for (i = x_max; i >= x; i--)
array[count++] = matrix[i][y];
if (++y > y_max) break;
}
return array;
}
总结
通过对数组的回顾,介绍了四种方法:
二分法、双指针法、滑动窗口法、模拟行为法
参考:《代码随想录》数组篇