数组基础知识回顾
数组的基础知识主要有声明与引用,赋值、遍历等,因为较常用,基本上都很熟悉,简单回顾一下动态数组的声明与引用。
静态数组在声明的时候就确定了数组的大小,并且不能修改,在实际中,经常会遇到这样一种情况,所需的空间取决于实际输入的数据,而无法预先确定,对于这种问题,可以使用动态数组来解决。
1、动态分配
一维数组:
int *array; // 数组指针
int arrLen; // 数组长度
int i; // 数组下标
array = (int*)malloc( arrLen*sizeof(int) );
二维数组:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i, row, column;
int **arr;
while (scanf("%d %d", &row, &column) != EOF) {
arr = (int **)malloc(sizeof(int *) * row); // 分配所有行的首地址
for (i = 0; i < row; i ++) { // 按行分配每一列
arr[i] = (int *)malloc(sizeof(int) * column);
}
// 释放开辟的二维数组空间
for (int i = 0; i < row; ++i)
{
free(*(arr + i));
}
}
return 0;
}
2、引用
使用数组下标,从0到n-1(n为数组长度)
回顾数组初级部分题
1、从排序数组中删除重复项
-
题目说明:
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 -
解题思路:
由于数组有序,使用两个指针从相邻的两个元素开始检查,如果相邻的两个元素不相同,就保留较小下标的元素值,将两个指针同时后移一位;如果两个元素值相同,保留较小下标元素的值,并将该指针向后移一位,另一个指针向后移动到与与该元素不相同为止;较大的指针指向数组的尾端就停止。 -
代码:
int removeDuplicates(int* nums, int numsSize) {
if (nums == NULL || numsSize <= 1)
return numsSize;
int i,j;
for (i=0,j=1; j<numsSize; ) {
if (nums[i] != nums[j]) {
nums[i+1] = nums[j];
i++;
j++;
continue;
} else {
j++;
continue;
}
}
return i+1;
}
2、买卖股票的最佳时机||(leetcode122)
- 题目说明:
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 - 解题思路
感觉这道题和数组的关系不大,解题的关键在与解题思路,用到的是贪心算法的思想,尽可能的获取当前最大的利益。 - 代码
int maxProfit(int* prices, int pricesSize) {
int i, profit=0;
for (i=0; i<pricesSize-1; i++) {
if (prices[i+1] > prices[i])
profit += prices[i+1] - prices[i];
}
return profit;
}
3、旋转数组
- 题目说明
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 - 解题思路
这道题在于对数组元素的操作,按照题目要求做即可,要求向右移动k个位置,可以分k次移动,每次向右移动一个位置,在移动的过程中,注意特殊位置的值。 - 代码
void rotate(int* nums, int numsSize, int k) {
int i, j;
int flag_value;
int temp;
/* 排除异常情况 */
if(k > numsSize)
{
k = k % numsSize;
}
else if(k == 0)
{
return;
}
/* 循环移位 */
while(k>0)
{
temp = nums[0];
for(i = numsSize - 1; i >= 0; i--)
{
if(i == numsSize - 1)
nums[0] = nums[i];
else
nums[i + 1] = nums[i];
}
nums[1] = temp;
k--;
}
}
4、存在重复
- 题目说明
给定一个整数数组,判断是否存在重复元素。如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。 - 解题思路
取第一个元素和其他元素比较,如果相同,则存在重复,直接返回;如果不相同,则依次取第二个、第三个……,如果取到最后一个还没有,就说明不存在重复的元素。这是一种笨办法。 - 代码
bool containsDuplicate(int* nums, int numsSize) {
int i = 0, j = 0;
for (i=0; i<numsSize-1; i++) {
for (j=i+1; j<numsSize; j++) {
if(nums[i]==nums[j])
return true;
}
}
return false;
}
5、只出现一次的数字(leetcode136)
- 题目说明
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 - 解题思路
我们学过一个运算符(^)它的作用是两个数的二进制中的每一个比特位,形同为0,不同则为1.即(1 ^ 1 = 0,50 ^ 50 = 0,0 ^ 100 = 100),那如果将这组数据每一位都^则最后的出的那个结果就是只出现一次的那个数。 - 代码
int singleNumber(int* nums, int numsSize) {
int i;
int result = nums[0];
for(i=1; i<numsSize; i++)
{
result =result^ nums[i];
}
return result;
}
6、两个数组的交集||
- 题目说明
给定两个数组,编写一个函数来计算它们的交集。 - 解题思路
先将两个数组排序,然后比较。 - 代码
int* intersect(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize) {
if(nums1Size==0||nums2Size==0)
return NULL;
sort(nums1,nums1Size);
sort(nums2,nums2Size);
int *res,i,j;
res=(int *)malloc(sizeof(int)*nums1Size);
*returnSize=0;
for(i=0,j=0;i<nums1Size&&j<nums2Size; )
{
if(nums1[i]<nums2[j])
i++;
else if(nums1[i]==nums2[j])
{
res[(*returnSize)++]=nums1[i];
i++;
j++;
}
else
j++;
}
return res;
}
//冒泡排序
void sort(int* nums, int numsSize)
{
int i,j;
for(i=numsSize-1; i>0; --i)
{
for(j=0; j<i; j++)
{
if(nums[j]>nums[j+1])
{
int temp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = temp;
}
}
}
}
7、加一(leetcode66)
- 题目说明
给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。 - 解题思路
从最低位加,满10进一。 - 代码
/**
* Return an array of size *returnSize.
* Note: The returned array must be malloced, assume caller calls free().
*/
int* plusOne(int* digits, int digitsSize, int* returnSize) {
int k = 1, i,n=0;
for(i = 0;i<digitsSize;i++)
{
if(digits[i]==9)
n++;
}
if(n==digitsSize)
{
digits[0] = 1;
digitsSize++;
for(i=1;i<digitsSize;i++)
digits[i]=0;
}
else
{
for(i=digitsSize-1; i>=0; i--)
{
if((digits[i]+k)>9)
{
digits[i] = digits[i]+k-10;
continue;
}
else
{
digits[i] = digits[i]+k;
k = 0;
}
}
}
*returnSize=digitsSize;
return digits;
}
8、移动零(leetcode283)
- 题目说明
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 - 解题思路
解法1:
从头开始遍历数组,当遇到数组中不为0的数字时,就把它们按顺序保存在数组里,跳过0,最后在数组后把0补上
解法2:
从头开始遍历数组,用变量cnt_zeros记录数组中0的个数,当遇到数组中为0的数时cnt_zeros加1,当遇到不为0的数时,将它们移动,它们前面有几个0就移动几步。 - 代码
//解法1
void moveZeroes(int* nums, int numsSize) {
int i,len=0;
for(i=0;i<numsSize;i++){
if(nums[i]!=0){
nums[len]=nums[i];
len++;
}
}
for(i=len;i<numsSize;i++)
nums[i]=0;
}
//解法2
void moveZeroes(int* nums, int numsSize) {
int i = 0;
int cnt_zeros = 0;
for(;i<numsSize;i++) {
if(nums[i]==0)
cnt_zeros++;
else if (cnt_zeros > 0){
nums[i-cnt_zeros] = nums[i];
nums[i] = 0;
}
}
}
9、两数之和
- 题目说明
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 - 解题思路
给定一个数,找另一个数,也是笨办法,注意static - 代码
int* twoSum(int* nums, int numsSize, int target) {
int i,j = 0;
static int twoSubscript[2];
for(i=0 ;i<numsSize; i++)
{
for(j=i+1 ;j<numsSize ;j++)
{
if(nums[i]+nums[j]==target)
{
twoSubscript[0]=i;
twoSubscript[1]=j;
return twoSubscript;
}
}
}
return twoSubscript;
}
10、有效的数独(leetcode36)
- 题目说明
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 - 解题思路
按照要求,判断,二维数组,操作有点复杂 - 代码
bool isValidSudoku(char** board, int boardRowSize, int boardColSize) {
int i, j, k;
/* 判断每行数组中的值是否只出现一次 */
for(k = 0; k < boardRowSize; k++)
{
for(i = 0; i < boardColSize - 1; i++)
{
for(j = i + 1; j < boardColSize; j++)
{
if(board[k][i] == '.')
break;
else if(board[k][j] == '.')
continue;
else if(board[k][i] == board[k][j])
return false;
}
}
}
/* 判断每列数组中的值是否只出现一次 */
for(k = 0; k < boardColSize; k++)
{
for(i = 0; i < boardRowSize - 1; i++)
{
for(j = i + 1; j < boardRowSize; j++)
{
if(board[i][k] == '.')
break;
else if(board[j][k] == '.')
continue;
else if(board[i][k] == board[j][k])
return false;
}
}
}
/* 判断3x3矩阵中的值是否只出现一次 */
int a = 0, b = 0, c = 0, d = 0;
int row = 0, col = 0;
int num;
for(num = 0; num < 9; num++)
{
for(a = row; a < 3 + row; a++)
{
for(b = col; b < 3 + col; b++)
{
/* 判断值为.,则判断下一个 */
if(board[a][b] == '.')
{
continue;
}
/* 判断3x3矩阵是否有相等的值 */
for(c = 0 + row;c < 3 + row; c++)
{
for(d = 0 + col; d < 3 + col; d++)
{
if(board[c][d] == '.')
continue;
else if((a != c) && (b != d) && (board[a][b] == board[c][d]))
return false;
}
}
}
}
/* 移动至下一个3x3矩阵 */
col += 3;
if(col >= 9)
{
col = 0;
row += 3;
}
}
return true;
}
11、旋转图像
- 题目说明
给定一个 n × n 的二维矩阵表示一个图像,将图像顺时针旋转 90 度。 - 解题思路
找元素旋转前后的规律 - 代码
void rotate(int** matrix, int matrixRowSize, int *matrixColSizes) {
int i, j;
int n = matrixRowSize;
for (i=0; i<n/2; i++) {
for(j=i; j<n-1-i; j++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[n-1-j][i];
matrix[n-1-j][i] = matrix[n-1-i][n-1-j];
matrix[n-1-i][n-1-j] = matrix[j][n-1-i];
matrix[j][n-1-i] = temp;
}
}
}