LeetCode刷题笔记(一)——初级算法——数组

目录

删除排序数组中的重复项

买卖股票的最佳时机 II

旋转数组

存在重复元素

只出现一次的数字

两个数组的交集 II

加一

移动零

两数之和

☆【留坑以后再补】☆

有效的数独

☆【留坑以后再补】☆

旋转图像


❤ 2021.8.26 ❤

知道LeetCode这个东西有一两年了,一见到就很有学习的冲动,但是自己太菜,一直做比较简单的硬件开发,没怎么接触过算法数据结构之类的东西,当时选了最简单的第一题就被劝退了,甚至我都不知道答题窗口里的函数结构怎么用。。。

前两天师妹心血来潮要刷LeetCode,我趁机也刷一刷也好有人能讨论讨论。

→→→时光倒流!

❤ 2021.8.24 ❤

今天的题目是

删除排序数组中的重复项

芜湖挺简单的,但是不会。。。

根据我多年来的考研经验,不会的题先背答案再说!

答案是这么说的

嗯。。。很好理解,然后(参考别人的答案)自己写了代码

int removeDuplicates(int* nums, int numsSize) 
{
    int left = 0;
    //双指针法
    for (int right = 1; right < numsSize; right++)
    {
        if (nums[left] != nums[right])
        {
            nums[++left] = nums[right];
        }
    }
    return ++left;
} 

 运行,没有问题,提交,得

经过我(对照别人的答案)缜密分析,发现可能是我没考虑空数组的情况于是

int removeDuplicates(int* nums, int numsSize) 
{
    int left = 0;
    //判断数组是否为空
    if (numsSize == 0)
        return 0;
    //双指针法
    for (int right = 1; right < numsSize; right++)
    {
        if (nums[left] != nums[right])
        {
            nums[++left] = nums[right];
        }
    }
    return ++left;
} 

这下没问题了

 

第一次成功提交答案,纪念一下。。。

再次特别感谢师妹,告诉我验证答案的时候要用printf。。。(用单片机的时候被printf虐待过的人飘过。。。)

另外师妹告诉我在vs里使用c语言需要新建空文件,然后添加源文件手动修改扩展名为.c才是真正用c语言的编译器编译的,学到了学到了。

然后我还看了另一种思路

大概意思就是通过遍历寻找相同项,然后按顺序依次把数组元素修改为相同元素中的最后一项。

感觉没有上一种方法那么好理解,但是异曲同工吧。

❤ 2021.8.25 ❤

今天的题目是

买卖股票的最佳时机 II

 

首先吐槽一下这个题目,你家买股票能知道未来n天的价格变化呀你是神仙么?

这次读完题目后我没有立刻查答案,而是先思考了一下。

我的思路是:

首先我把所有情况都计算出来,算出每种买卖方式的能挣到的钱,然后取最大值。

想法很简单,在写代码的时候遇到问题,就是我并不知道题目给出的天数具体有几天,也就是说不知道数组的成员数,可能会有很长的一个数组,于是在写代码的时候不能用for循环,因为不知道需要嵌套几层。我想到用递归的方法去做,但是感觉有点复杂(而且我不会。。。),于是我还是去看了答案。。。

答案有几种思路,第一种是动态规划,用递推公式

有点复杂,大概看懂了,但是代码实现有点复杂,我看了下一种思路。

这个就很有意思了,用下面网友的话说就是

我的理解就是,明天要涨我就买(或手里有股票不操作),明天要跌我就卖(或手里没股票不操作),只要一分不亏,最后一定能得到最大收益。

然后我写了代码

int maxProfit(int* prices, int pricesSize) 
{
	int iProfit = 0;
	if (pricesSize == 0)
		return 0;
	for (int i = 0; i < pricesSize - 1; i++)
	{
		int j = prices[i + 1] - prices[i];
		if (j > 0)
			iProfit = iProfit + j;
	}
	return iProfit;
}

OK没有问题,提交

 

喵喵喵?这评分也太低了吧!

不过我还是要吐槽一下,python真香!

❤ 2021.8.26 ❤

今天的题目是

旋转数组

第一眼看到这个题目,我去好简单啊哈哈哈(pia打脸)

我的想法是这样的:

1、最简单的方法当然是建立临时数组,但是内存占用较多,空间复杂度肯定不达标。

2、于是我想到可以每次只移动一位,循环k次。

代码如下

void rotate2(int* nums, int numsSize, int k)
{
	int Temp;
	if (k == 0)
		return 0;
	k %= numsSize;
	for (int i = 1; i < k + 1; i++)
	{
		Temp = nums[numsSize - 1];
		for (int j = numsSize - 1; j > 0; j--)
		{
			nums[j] = nums[j - 1];
		}
		nums[0] = Temp;
	}
}

这个代码呢,经过测试是没有问题的,但是。。。

耗时太长了。。。晕

3、于是我换了一种思路,在参考了答案之后,我尝试了这个环形移动的方法

每次替换第ik个元素,当ik超过数组长度时取余,代码如下

void rotate3(int* nums, int numsSize, int k)
{
	int Temp1,Temp2;
	if (k == 0)
		return 0;
	k %= numsSize;

	Temp1 = nums[0];
	for (int i = 0; i < numsSize; i++)
	{
		Temp2 = nums[((i + 1) * k) % numsSize];
		nums[((i + 1) * k) % numsSize] = Temp1;
		Temp1 = Temp2;
	}
}

 但是。。。但是!我遇到了参考答案里说的,数组长度是k的整数倍的问题,答案里说用visit函数,过滤掉已经访问过的元素,但是我不知道在c语言里怎么用,所以pass。。。

4、最后我用了多次反转的方法(这种方法是怎么想出来的!!??)

代码如下

void reverse(int* nums,int start,int end)
{
	while (end > start)
	{
		int temp = nums[start];
		nums[start] = nums[end];
		nums[end] = temp;
		start++;
		end--;
	}
}

void rotate(int* nums, int numsSize, int k)
{
	if (k == 0)
		return 0;
	k %= numsSize;
	reverse(nums, 0, numsSize-1);
	reverse(nums, 0, k - 1);
	reverse(nums, k, numsSize-1);
}

 还要自己写reverse()函数,就挺麻烦。。。

而且我第一次提交的时候没注意reverse()函数和rotate()函数的元素对应问题,提交之后报错了

我就很奇怪,为啥别人的代码和我的差不多,但是速度就比我快了不止一点半点。。。

❤ 2021.8.27 ❤

今天的题目是

存在重复元素

 看到题目之后第一反应依然是:呵,简单。

然后。。。

WTF!暴力检索方法居然不让用。

然后我想到了先排序再判断的方法,然后就涉及到排序算法的问题,关于排序我只知道冒泡,但是考虑到冒泡排序的效率。。。。。。

然后我就看了答案。

不看不知道,一看吓一跳,他居然直接调用C语言自带的排序函数!

然后我不得不去学习了下这个函数qsort()。

关于这个函数我查到了这位老哥的文章,讲的还挺详细。

C语言qsort函数用法

这个函数比较特别的地方是需要自己定义一个比较函数,然后通过回调函数的形式来调用,实现数组的排序。

在这里用到的是这个函数

int cmp(const void* _a, const void* _b) {
	int a = *(int*)_a, b = *(int*)_b;
	return a - b;
}

 至于为什么这样写,我查了一些资料得出的结论是:就是这样规定的。。。

除此之外当比较的数组类型不同时,需要把比较函数进行相应修改,见老哥文章。

有了这个排序函数之后就非常简单了

int cmp(const void* _a, const void* _b) {
	int a = *(int*)_a, b = *(int*)_b;
	return a - b;
}

bool containsDuplicate(int* nums, int numsSize)
{
	if (numsSize == 0)
		return 0;
	qsort(nums, numsSize, sizeof(int), cmp);
	for (int i = 0; i < numsSize-1; i++)
	{
		if (nums[i] == nums[i + 1])
			return true;
	}
	return false;
}

 

好像还不错(不愧是官方答案。。。)

另外在vs环境下调试过程中需要注意想使用bool类型和qsort()函数需要添加对应的头文件

#include <stdbool.h>
#include <stdlib.h>

❤ 20210.8.28 ❤

今天的题目是

只出现一次的数字

看到题之后:这题昨天不是做过吗?不就是先排序再检索吗?有难度吗?(pia~!)

int cmp(const void* _a, const void* _b) 
{
	int a = *(int*)_a, b = *(int*)_b;
	return a - b;
}

int singleNumber(int* nums, int numsSize) 
{
	qsort(nums, numsSize, sizeof(int), cmp);
	if (numsSize == 1)
	{
		return nums[0];
	}
	else if (numsSize > 1)
	{
		if (nums[0] != nums[1])
		{
			return nums[0];
		}
		else
		{
			for (int i = 1; i < numsSize - 1; i++)
			{
				if (nums[i] != nums[i - 1] && nums[i] != nums[i + 1])
					return nums[i];
			}
			return nums[numsSize - 1];
		}
	}
	else
		return 0;
}

 

提交之后我觉得我真是越来越厉害了,完全抓住了命题人的思路哈哈哈。。。

然后我一看答案,傻眼

这TM谁想得到啊!

不过这种方法是真的简单(人和人的差距咋就那么大捏。。。)

int singleNumber(int* nums, int numsSize)
{
	for (int i = 1; i < numsSize; i++)
	{
		nums[0] ^= nums[i];
	}
	return nums[0];
}

 这里需要注意的地方,为了节省存储空间,所以这里用了nums[0]作为存储最终结果的变量,所以for循环要从i=1开始,一开始没注意,结果就错了。

 

唉。。。

❤ 2021.8.30 ❤

今天的题目是

两个数组的交集 II

看完题目之后我没有什么想法。。。。

经过一番思考,我觉得可以这样:

我新建一个数组,然后检索数组2里面有没有数组1的元素,如果有就将其复制到新数组里,为了防止重复检索,把检索过的元素都修改为一个两个数组里不同是存在的数字,检索完成后新数组里就是两个数组的交集。但是怎么找到这个两个数组里都没有的数字呢,我的想法是在检索之前先从0开始遍历两个数组,直到找到一个数两个数组里不同时存在为止。

我觉得想法可行,但是傻傻的。。。

而且在c语言实现函数里有这么一句话:

我查了半天大概明白了,这里需要动态分配新数组的内存空间。

而且c语言这里有一个参数很奇怪,叫“returnSize”,我看了半天别人的答案才明白过来,这个是用户定义的一个参数,用来存放交集数组的长度的。就很奇怪哈,直接return不行么?然后我又一想,好想数组是动态分配的,他的地址也需要传回来,真麻烦。。。

关于动态分配内存,大概是应用malloc() 函数。

使用的话是这样

str = (char *) malloc(15);

根据我查阅资料的深入,我发现有这么几个函数的功能类似

malloc(), calloc()和 realloc() ,关于这几个函数的区别我就不搬了,见这位老哥

malloc()与calloc区别

关于所用的算法,主要有两种,一个是先排序再用双指针法,一个是用map(映射表)。

双指针法还是很好理解的,在排序之后,依次比较两个数组元素的大小,哪个小哪个下标就加一,直到找到相同的元素,并将其存到新数组里。

int cmp(const void* _a, const void* _b)
{
	return *(int*)_a - *(int*)_b;
}


/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* intersect(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize) {
	qsort(nums1, nums1Size, sizeof(int), cmp);
	qsort(nums2, nums2Size, sizeof(int), cmp);
	*returnSize = 0;
	int* intersection = (int*)malloc(sizeof(int) * fmin(nums1Size, nums2Size));
	int i1 = 0 , i2 = 0;
	while (i1 < nums1Size && i2 < nums2Size)
	{
		if (nums1[i1] > nums2[i2])
			i2++;
		else if (nums1[i1] < nums2[i2])
			i1++;
		else
		{
			intersection[*returnSize] = nums1[i1];
			i1++;
			i2++;
			(*returnSize)++;
		}
	}
	return intersection;
}

我在调试的时候遇到一个问题

经过我多方比较发现是这里没有加括号。。。

加上括号就没问题了,还是我以前缺少指针使用的经验。

另外函数里使用了fmin()函数,需要添加math.h库。

关于其他的方法,用的是哈希表,map等的方法,这些东西对我来说还有点难度,应用起来有点困难,不过用刻师傅的话说,心有所向,日复一日,必有进益!

set(集合),map(映射表)都属于关联式容器。

来源:关联式容器

还有这个

map和set的概念及使用

然后我又了解了下什么是红黑树

红黑树(RB-Tree)

看完之后虽然还是不太了解,但是以后再看到的话就可以说,嗯,我知道。。。

❤ 2021.8.31 ❤

今天的题目是

加一

我的思路:

就很简单嘛!当年用单片机做时钟的时候这是最基础的问题了哈哈哈!(pia!)

我一开始的想法是,最末尾加一之后判断是否为10,如果超了就改为0并把前一位加一,以前在单片机上就是这么做的。可是我一想,因为数组的位数是不确定的,当我如果判断到最后一位时仍然需要进位,那我整个数组的所有元素都需要往后挪一格,好麻烦呀。

所以我又想,可不可以我先判断出运算后的数字长度,然后再分配内存呢?于是我先把数组存放的数字计算出来,然后+1,然后用除以10的方法判断出其位数,同时得到returnSize的大小,然后分配内存,将数字分别存储到数组里。

代码如下

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* plusOne(int* digits, int digitsSize, int* returnSize){
	int temp = 0;
	for (int i = 0; i < digitsSize; i++)
	{
		temp += digits[i] * pow(10, (digitsSize - 1 - i));
	}
	temp++;
	int jixu = temp;
	int wei = 1;
	if (jixu == 0)
	{
		*returnSize = 1;
	}
	else
	{
		while (jixu != 0)
		{
			jixu /= 10;
			wei++;
		}
		*returnSize = wei-1;
	}
	
	int* returnarray = (int*)malloc(sizeof(int) * (*returnSize));
	for (int i = 0; i < (*returnSize); i++)
	{
		returnarray[i] = temp / pow(10, (*returnSize) - 1 - i);
		temp = temp % (int)pow(10, (*returnSize) - 1 - i);
	}
	return returnarray;
}

在经过几次测试之后没有问题,于是我就提交了,于是就报错了

我经过简单分析,发现是内存溢出了,因为数组比较长,所以int型变量吃不消,然后我又换成long型依然吃不消,于是我觉得这个方法是有问题的。

 

 长整型变量最大可以到这么多,而数组对多有100位。

看来只能用逐位判断的方法了,不过我还是要吐槽一下,测试数组里面有{0}真是很让人烦恼啊。。。

这次的思路是,首先把最后一个元素+1,然后进入倒序循环,判断是否为10,如果是则写为0,并把前一个元素+1,依次循环至下标为1的元素。然后判断下标为0的元素是否为10,如果不是则将数组复制到新数组内,numsSize为digitsSize,如果是则numsSize为digitsSize+1,然后新数组前两位为1和0,从第三位开始复制原数组的第二位。

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* plusOne(int* digits, int digitsSize, int* returnSize){
	digits[digitsSize - 1]++;
	for (int i = digitsSize - 1; i >0; i--)
	{
		if (digits[i] == 10)
		{
			digits[i] = 0;
			digits[i-1]++;
		}
	}
	int* returnarray = (int*)malloc(sizeof(int) * (digitsSize + 1));
	if (digits[0] == 10)
	{
		*returnSize = digitsSize + 1;
		returnarray[0] = 1;
		returnarray[1] = 0;
		for (int i = 2; i < (*returnSize); i++)
		{
			returnarray[i] = digits[i - 1];
		}
	}
	else
	{
		*returnSize = digitsSize;
		for (int i = 0; i < (*returnSize); i++)
		{
			returnarray[i] = digits[i ];
		}
	}
	return returnarray;
}

通过了!

不过调试的时候遇到了一个小问题,我在第一个for循环的地方一开始写成了i>1,于是造成了循环不会遍历到下标为0的元素,改成i>0或者i=1就好了。

蓝后我看了看别人的代码,和我的大概意思差不多,但是还是有细节不一样的地方

我要吐槽一下,人家的语言都可以直接在原数组上增加删除,为啥c语言不行。。。

❤ 2021.9.1 ❤

今天的题目是

移动零

 我的思路:

就很简单嘛!这一看就是双指针啊!

话不多说,上代码

void moveZeroes(int* nums, int numsSize) {
	int i = 0;
	while (i < numsSize && nums[i] != 0)
	{
		i++;
	}
	if (i == numsSize)
		return 0;
	for (int j=i; j < numsSize; j++)
	{
		if (nums[j] != 0)
		{
			nums[i] = nums[j];
			i++;
		}
	}
	for (int k = i; k < numsSize; k++)
	{
		nums[k] = 0;
	}
	return 0;
}

思路就是先找到第一个0的位置,如果没有0就返回,然后把后面非零的逐次替代过去。

 一次通过,问题不大

然后我又看了别人的代码,发现我的第一步有点多余,不需要特意去判断第一个0在哪里,直接把非零项覆盖时,如果其前面没有0,则相当于替换自己。

优化代码 

void moveZeroes(int* nums, int numsSize) {
	int i = 0;
	for (int j = 0; j < numsSize; j++)
	{
		if (nums[j] != 0)
		{
			nums[i] = nums[j];
			i++;
		}
	}
	for (int k = i; k < numsSize; k++)
	{
		nums[k] = 0;
	}
	return 0;
}

挡当~!

❤ 2021.9.2 ❤

今天的题目是:

两数之和

说起来,这道题还有点特殊意义,因为这是我当年第一次接触leetcode时选择的题,然后就被劝退了。。。今天又看到了别有一番滋味。

我的思路:

 第一个想到的就是双指针遍历呗,一个一个去计算和,找到为止。

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* twoSum(int* nums, int numsSize, int target, int* returnSize) 
{
	int i = 0, j = 0;
	int* returnarray = (int*)malloc(sizeof(int) * 2);
	*returnSize = 2;
	for (i = 0; i < numsSize - 1; i++)
	{
		j = i + 1;
		while (j < numsSize)
		{
			if (nums[i] + nums[j] != target)
				j++;
			else
			{
				returnarray[0] = i;
				returnarray[1] = j;
				return returnarray;
			}
		}
	}
	return 0;
}

一次通过,耶!

之前一直都在用c语言的方法来解决,但是看到很多稍微复杂一点的方法,c语言实现起来就很麻烦,相对来说C++和python实现起来就很顺滑。。。于是今天先来尝试一下C++。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int i = 0, j = 0;
		for (i = 0; i < nums.size() - 1; i++)
		{
			j = i + 1;
			while (j < nums.size())
			{
				if (nums[i] + nums[j] != target)
					j++;
				else
				{
					return { i,j };
				}
			}
		}
		return {};
    }
};

不得不说代码确实简介了很多

执行时间也慢了很多。。。

还有需要注意的是c++调试的时候用vs要这样调用

#include <iostream>
#include <vector>

using namespace std;



class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int i = 0, j = 0;
		for (i = 0; i < nums.size() - 1; i++)
		{
			j = i + 1;
			while (j < nums.size())
			{
				if (nums[i] + nums[j] != target)
					j++;
				else
				{
					return { i,j };
				}
			}
		}
		return {};
    }
};

int main()
{
    vector<int> a = { 2,7,11,15 };
    int target = 9;
    Solution S;
    vector<int> k = S.twoSum(a, target);
    for (int i = 0; i < k.size(); i++)
    {
        cout << k[i] << "," ;
    }
}

 然后c++里面好像不用普通的数组,而是用vector来建立数组,相对来说能省很多麻烦。

关于vectorC++ vector 容器浅析

然后我还试了python,但是python我基本不会,所以这是抄来的代码

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        for i in range(n):
            for j in range(i + 1,n):
                if nums[i] + nums[j] == target:
                    return[i,j]
        return []

python的解题代码有了,但是怎么在电脑上测试成了问题。再咨询过张仕政大神之后知道了大概是得这样

from typing import List


class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        for i in range(n):
            for j in range(i + 1,n):
                if nums[i] + nums[j] == target:
                    return[i,j]
        return []


if __name__ == '__main__':
    list1 = [1, 2, 3, 4, 5]
    target = 3
    inst = Solution()
    print(inst.twoSum(list1, target))

学到了学到了。

另外,今天这道题的进阶版是使用哈希表来完场,我简单了解了下

数据结构 Hash表(哈希表)

哈希表(散列表)原理详解

哈希表的原理及实现代码

嗯,了解完了,下面是抄答案时间

☆【留坑以后再补】☆

❤ 2021.9.3 ❤

今天的题目是

有效的数独

这题看起来还挺复杂的,我遇到的第一个问题就是在vs里面表示这个二维数组。

board = 
[["5","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]

经过师妹提醒, 要写成单引号

	char a[9][9] = 
	    { 
		{ '5', '3', '.', '.', '7', '.', '.', '.', '.' },
		{ '6', '.', '.', '1', '9', '5', '.', '.', '.' },
		{ '.', '9', '8', '.', '.', '.', '.', '6', '.' },
		{ '8', '.', '.', '.', '6', '.', '.', '.', '3' },
		{ '4', '.', '.', '8', '.', '3', '.', '.', '1' },
		{ '7', '.', '.', '.', '2', '.', '.', '.', '6' },
		{ '.', '6', '.', '.', '.', '.', '2', '8', '.' },
		{ '.', '.', '.', '4', '1', '9', '.', '.', '5' },
		{ '.', '.', '.', '.', '8', '.', '.', '7', '9' } 
    	};

然后呢数组有点大啊,就没啥思路,于是不得不看答案。。。

一看答案豁然开朗,没什么是暴力方法不能解决的,用多重循环依次遍历每个元素的横、竖、小方块内是否有和他相同数值的元素就可以了,需要注意的是检索小方块内时注意for循环的其实数值和判定条件的。

bool isValidSudoku(char** board, int boardSize, int* boardColSize) 
{
	for (int i = 0; i < boardSize; i++)
	{
		for (int j = 0; j < *boardColSize; j++)
		{
			if (board[i][j] != '.')
			{
				for (int x = 0; x < boardSize; x++)
				{
					if (x != i && board[i][j] == board[x][j])
						return false;
				}
				for (int y = 0; y < *boardColSize; y++)
				{
					if (y != j && board[i][j] == board[i][y])
						return false;
				}
				//这里注意初始值
				for (int z1 = i / 3 * 3; z1 < i / 3 * 3 + 3; z1++)
				{
					for (int z2 = j / 3 * 3; z2 < j / 3 * 3 + 3; z2++)
					{
						if (z1 != i && z2 != j && board[i][j] == board[z1][z2])
							return false;
					}
				}
			}
		}
	}
	return true;
}

哦哟成绩还不错。

相对于这道题的解法,我觉得我受益更大的是摸索到了二维数组的调用方法。

这道题的数组是通过一个char**变量来传递的,也就是一个指向字符串型指针的指针。最开始我直接把二维数组的地址传递给函数,然后就报错了,经过查阅资料终于搞清楚怎么回事,感谢以下几位老哥

C语言函数传递二维数组

深入 理解char * ,char ** ,char a[ ] ,char *a[] 的区别

我的c语言测试函数是这样的

int main()
{
	char a[9][9] = 
	{ 
		{ '5', '3', '.', '.', '7', '.', '.', '.', '.' },
		{ '6', '.', '.', '1', '9', '5', '.', '.', '.' },
		{ '.', '9', '8', '.', '.', '.', '.', '6', '.' },
		{ '8', '.', '.', '.', '6', '.', '.', '.', '3' },
		{ '4', '.', '.', '8', '.', '3', '.', '.', '1' },
		{ '7', '.', '.', '.', '2', '.', '.', '.', '6' },
		{ '.', '6', '.', '.', '.', '.', '2', '8', '.' },
		{ '.', '.', '.', '4', '1', '9', '.', '.', '5' },
		{ '.', '.', '.', '.', '8', '.', '.', '7', '9' } 
	};
	int b = 9;
	int c = 9;
	char* p[9];
	for (int i = 0; i < c; i++)
	{
		p[i] = a[i];
	}
	bool k = isValidSudoku(p, b, &c);
	printf("%d", k);
}

这里还要吐槽下原题,既然 boardSize是int,为啥boardColSize就变成了int*。。。。

通过使用c语言和暴力检索方法,虽然完成了任务,但是不完美,我在查看答案的过程中看到了应用哈希表思想的解法,于是用c++试着实现了下

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        unordered_map<char, int> hashtable;
        //初始值很重要
        int check[3][9][9] = { 0 };
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                if (board[i][j] != '.')
                {
                    if ((++check[0][board[i][j] - '1'][i] > 1) ||
                        (++check[1][board[i][j] - '1'][j] > 1) ||
                        (++check[2][board[i][j] - '1'][(i / 3) * 3 + j / 3] > 1))
                        return false;
                }
            }
        }
        return true;
    }
};

当然这段代码是抄来的,因为我觉得就很巧妙。

首先他用了哈希表的思想,但是又没有完全用哈希表,思想就是先建立3个新数组,把原数组按行、列、块分别将数值与下标对应。在遍历过程中,当遇到一个数值时对所在新数组对应元素+1,并判断改数值是否已经被记录过,如果被记录过(>1),则返回false。

另外,c++的调用函数也简单了很多(真香)

int main()
{
    vector<vector<char>> a =
    {
    { '5', '3', '.', '.', '7', '.', '.', '.', '.' },
    { '6', '.', '.', '1', '9', '5', '.', '.', '.' },
    { '.', '9', '8', '.', '.', '.', '.', '6', '.' },
    { '8', '.', '.', '.', '6', '.', '.', '.', '3' },
    { '4', '.', '.', '8', '.', '3', '.', '.', '1' },
    { '7', '.', '.', '.', '2', '.', '.', '.', '6' },
    { '.', '6', '.', '.', '.', '.', '2', '8', '.' },
    { '.', '.', '.', '4', '1', '9', '.', '.', '5' },
    { '.', '.', '.', '.', '8', '.', '.', '7', '9' }
    };
    Solution S;
    bool k = S.isValidSudoku(a);
        cout << k;
}

关于c++用vector建立的二维数组如何查看长度,见

C++ vector二维数组初始化以及获取数组长度

然后关于用python的解法

☆【留坑以后再补】☆

❤ 2021.9.4 ❤

今天的题目是

旋转图像

看完题之后我的感觉就是。。。没啥思路,以前在matlab里面旋转图像那不就是一个指令的事情?现在自己搞还有点不知所措。

思考之后我的想法是找规律,然后一个一个的去替换,但是找了半天没找到,焦灼之下看了答案,我这个想法虽然不算是巧妙但也是能够实现的方法,至于规律这位老哥总结的很好

再一看我发现这个规律也不是那么难找

变换之后的i是原来的j,原来的i和现在的j相加为n-1,嘿嘿。。。

上代码

开始我傻了,想要一个一个去去交换,但是这样是不对的

void rotate(int** matrix, int matrixSize, int* matrixColSize) {
	int temp1 = 0, temp2 = 0;
	int n = matrixSize;
	temp2 = matrix[0][0];
	for (int i = 0; i < matrixSize; i++)
	{
		for (int j = 0; j < *matrixColSize; j++)
		{
			temp1=matrix[j][n - 1 - i];
			matrix[j][n - 1 - i] = temp2;
			temp2 = temp1;
		}
	}
	matrix[0][0] = temp2;
	return 0;
}

 经过思考加上看答案,其实每次旋转一定是4个一起转,同时遍历只需要进行四分之一个矩阵(奇偶区别就是多一行)

void rotate(int** matrix, int matrixSize, int* matrixColSize) {
	int temp;
	int n = matrixSize;
	for (int i = 0; i < (n+1)/2; i++)
	{
		for (int j = 0; j < n / 2; j++)
		{
			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;
		}
	}
	return 0;
}

 提交

此外还有先绕水平轴翻转,再绕对角线翻转的解法,就挺神奇的。

另外,用python的大佬给出了非常简短的解法,今天时间有限就不去探究了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值