注:本文部分内容及所有题目源自于Leetcode网站[1],仅供本人自己学习与作为练习笔记使用。(所有引用都已标注原网址,见文章或附录。若存在版权侵犯,请联系本人删除侵权内容。)
日期Oct.21 - Oct.27 2020(每日一题)
Ps:本周开始按模块刷题了,依旧是每日一题,但是题目难度会根据模块刷的次数逐渐递增。周与周之间会交替着刷不同的模块。
- 本周模块:数组
- 数组是目前Leetcode上题量最多的一个模块了。刷题前我们来了解一下什么是数组:
- 数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。
- 首先,数组会利用 索引 来记录每个元素在数组中的位置,且在大多数编程语言中,索引是从 0 算起的。我们可以根据数组中的索引,快速访问数组中的元素。事实上,这里的索引其实就是内存地址。
- 其次,作为线性表的实现方式之一,数组中的元素在内存中是 连续 存储的,且每个元素占用相同大小的内存。
- 例如对于一个数组 ['oranges', 'apples', 'bananas', 'pears', 'tomatoes'],为了方便起见,我们假设每个元素只占用一个字节,它的索引与内存地址的关系如下图所示。
- 在具体的编程语言中,数组的实现方式具有一定差别。比如 C++ 和 Java 中,数组中的元素类型必须保持一致,而 Python 中则可以不同。相比之下,Python 中的数组(称为 list)具有更多的高级功能。
以上文字描述均来自 LeetCode数组模块[2]
Ps:第一周我们完成的 #867. 转置矩阵,977. 有序数组的平方 就是属于涉及到数组的题。
1. 题目面试题 17.10. 主要元素(难度:简单)Oct.21
- 刷题请点击或见附录:面试题 17.10. 主要元素[3]
- 题目要求:
示例 1:
输入:[1,2,5,9,5,9,5,5,5]
输出:5
示例 2:
输入:[3,2]
输出:-1
示例 3:
输入:[2,2,1,1,1,2,2]
输出:2
1.1 解题思路
- 我们先对数组做排序,然后判断同一元素是否占有数量大于列表长的一半,也就是判断nums[i] == nums[i+nums.size()/2]是否成立即可,不成立就取下一个数,直到取到过数组长度一半即可。
1.2 代码
- python 3 代码
class Solution:
def majorityElement(self, nums: List[int]) -> int:
size= len(nums)
if(size>0):
nums.sort()
for i in range (0,(size+1)//2):#这里要注意我们要做的是除数取商因为for循环只支持int类型,若数组正好是偶数 *(size+1)/2* 的运算 会自动输出float类型 所以我们用取余符号 *//*
if (nums[i]==nums[i+size//2]):
return nums[i]
return -1
- C++ 代码
class Solution {
public:
int majorityElement(vector<int>& nums) {
int size = nums.size();
if(size>0){
sort(nums.begin(),nums.end());//sort快速排序
for(int i = 0;i1)/2;i++){//循环只需要做到数组长的一半就可以了,条件也可以改成i<= size/2
if(nums[i] == nums[i+size/2]){
return nums[i];
}
}
}
return -1;//数组<=0或者没有主要元素
}
};
2. 题目1588. 所有奇数长度子数组的和(难度:简单)Oct.22
刷题请点击或见附录:1588. 所有奇数长度子数组的和[4]
题目要求:给你一个正整数数组 arr ,请你计算所有可能的奇数长度子数组的和。
子数组 定义为原数组中的一个连续子序列。
请你返回 arr 中 所有奇数长度子数组的和。
示例 1:
输入:arr = [1,4,2,5,3]
输出:58
解析输出过程:所有奇数长度子数组和它们的和为:
[1] = 1
[4] = 4
[2] = 2
[5] = 5
[3] = 3
[1,4,2] = 7
[4,2,5] = 11
[2,5,3] = 10
[1,4,2,5,3] = 15
我们将所有值求和得到 1 + 4 + 2 + 5 + 3 + 7 + 11 + 10 + 15 = 58
示例2
输入:arr = [1,2]
输出:3
解释:总共只有 2 个长度为奇数的子数组,[1] 和 [2]。它们的和为 3 。
示例3
输入:arr = [10,11,12]
输出:66
2.1 解题思路
- 用三个 for 循环来写。
- 第一个 for 循环用来改变子数组的大小(可以看做为是一个窗口)
- 第二个 for 循环用来移动窗口,获得等长的子数组
- 第三个 for 循环用来计算数组的和。
2.2 代码
- python 3 代码
#python 我们可以比C++少写一个循环。因为有现成的求和函数sum
class Solution:
def sumOddLengthSubarrays(self, arr: List[int]) -> int:
l=len(arr)
ans=0
for i in range (1,l+1,2):
for n in range (l-i+1):
ans=ans+sum(arr[n:n+i])
return ans
- C++ 代码
class Solution {
public:
int sumOddLengthSubarrays(vector<int>& arr) {
int l=arr.size();
int ans=0;
for(int n = l;n>0;n=n-2)//改变子数组的大小
for(int i=0;i//移动窗口,获得等长的子数组for(int j=i;j1;j++){
ans= ans+arr[j];
}//计算数组的和return ans;
}
};
3. 题目628. 三个数的最大乘积(难度:简单)Oct.23
- 刷题请点击或见附录:628. 三个数的最大乘积[5]
- 题目要求:给定一个整型数组,在数组中找出由三个数,组成的最大乘积,并输出这个乘积。
示例 1:
输入: [1,2,3]
输出: 6
示例 1:
输入: [1,2,3,4]
输出: 24
注意:
给定的整型数组长度范围是[3,10^4],数组中所有的元素范围是[-1000, 1000]。
输入的数组中任意三个数的乘积不会超出32位有符号整数的范围。
3.1 解题思路
先对数组做一个快速排序,然后做其中三个数的乘积,比较乘积的最大值,并且返回值。
做乘积的时我们需要获得一个最大的正数,存在以下两种情况:
- 2个最小的负数和1个最大的正数
- 3个最大的正数
Ps:很多人问为什么要先做乘积。其实是出于数组内可以存在负数的考虑,两个负数的乘积可以变为正数,从而影响到乘积的最大值。
3.2 代码
- python 3 代码
class Solution:
def maximumProduct(self, nums: List[int]) -> int:
a=len(nums)
nums.sort()
maybeMax1=nums[0]*nums[1]*nums[a-1]
maybeMax2=nums[a-3]*nums[a-2]*nums[a-1]
return max(maybeMax1,maybeMax2)
- C++ 代码
class Solution {
public:
int maximumProduct(vector<int>& nums) {
sort(nums.begin(),nums.end());//快速排序nums
int a = nums.size();//获取数组大小
int maybeMax1=0;
int maybeMax2=0;
maybeMax1=nums[0]*nums[1]*nums[a-1];//可能性1
maybeMax2=nums[a-3]*nums[a-2]*nums[a-1];//可能性2
return max(maybeMax1,maybeMax2);//比较返回最大值
}
};
4. 题目1550. 存在连续三个奇数的数组(难度:简单)Oct.24
- 刷题请点击或见附录:1550. 存在连续三个奇数的数组[6]
- 题目要求:给你一个整数数组 arr,请你判断数组中是否存在连续三个元素都是奇数的情况:如果存在,请返回 true ;否则,返回 false 。
示例 1:
输入:arr = [2,6,4,1]
输出:false
解释:不存在连续三个元素都是奇数的情况。
示例 2:
输入:arr = [1,2,34,3,4,5,7,23,12]
输出:true
解释:存在连续三个元素都是奇数的情况,即 [5,7,23] 。
4.1 解题思路
- 做一个累加循环,循环次数是数组长度减去3,在循环内部做一个多条件的 if语句 ,符合条件输出 ture ,不符合则继续循环,直到循环结束,若还无符合条件的序列,则输出 false 。
4.2 代码
- python 3 代码
class Solution:
def threeConsecutiveOdds(self, arr: List[int]) -> bool:
for i in range (0,len(arr)-2):
if (arr[i]%2==1 and arr[i+1]%2==1 and arr[i+2]%2==1):
return True
return False
- C++ 代码
class Solution {
public:
bool threeConsecutiveOdds(vector<int>& arr) {
int length=arr.size();
for(int i=0 ;i-2;i++){if((arr[i]%2==1)&&(arr[i+1]%2==1)&&(arr[i+2]%2==1)){return true;
}
}return false;
}
};
5. 题目219. 存在重复元素 II(难度:简单)Oct.25
- 刷题请点击或见附录:219. 存在重复元素 II[7]
- 题目要求:给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。
示例 1:
输入: nums = [1,2,3,1], k = 3
输出: true
示例 2:
输入: nums = [1,0,1,1], k = 1
输出: true
示例 3:
输入: nums = [1,2,3,1,2,3], k = 2
输出: false
5.1 解题思路
- python代码使用了字典的查找方法,实现过程与c++的hashmap类似。
- c++代码使用hashmap,计算元素是否出现,如果出现过则计算下标的差值是否小于等于 k。
5.2 代码
- python 3 代码
class Solution:
def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
dic = {}#初始化dictionary 元素存入key,索引存入value
for i in range(len(nums)):
if nums[i] in dic:
#如果有相同元素,匹配成功
#判断索引差是否小于或等于k符合条件
if i - dic[nums[i]] <= k:
return True
else:
dic[nums[i]] = i #差不小于等于k,则更新索引到最新
else:
dic[nums[i]] = i #若不在字典中,则更新索引
return False
- C++ 代码
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
unordered_map<int, int> map;
for(int i=0; i if(map.count(nums[i]) && i - map[nums[i]] <= k){
return true;
}
map[nums[i]] = i;
}
return false;
}
};
6. 题目605. 种花问题(难度:简单)Oct.26
刷题请点击或见附录:605. 种花问题[8]
题目要求:假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给定一个花坛(表示为一个数组包含0和1,其中0表示没种植花,1表示种植了花),和一个数 n 。能否在不打破种植规则的情况下种入 n 朵花?能则返回True,不能则返回False。
示例 1:
输入:flowerbed = [1,0,0,0,1], n = 1
输出: True
示例 2:
输入: flowerbed = [1,0,0,0,1], n = 2
输出: False
6.1 解题思路
- 使用窗口挪动的办法,去计算可用的种植位置
- 挪动窗口的过程中我们需要注意的是,连续五个空位可能会造成,连续3个可以种植的位置的假象。所以我们每一次确定了种植位置以后,应该把该位置的值更新到 1 标记为已种植,防止计算相邻位置。每更新一个位置,我们的计数器 count 将做一次累加。最后比较 count 与 n 的值的比较, 大于等于返回 True ,反之返回 False。
- 在此需要注意的是在大小为3的窗口挪动中,我们需要先对花床数组,做一个预处理,即前后加一个 0 位置。原理类似于做神经网络中的卷积(Convolution)[9]的原理。Ps:后面我会整理所有上过的课的笔记,关于卷积具体的内容会在已经学过的神经信息网络课程中详细介绍到。
6.2 代码
- python 3 代码
#具体注释在下方C++代码中,基本一样
class Solution:
def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool:
flowerbed=[0]+flowerbed
flowerbed=flowerbed+[0]
count=0
for i in range (1,len(flowerbed)-1):
if(flowerbed[i-1]==0 and flowerbed[i+1]==0 and flowerbed[i]==0):
count +=1
flowerbed[i]=1
if count>=n:
return True
else:
return False
- C++ 代码
class Solution {
public:
bool canPlaceFlowers(vector<int>& flowerbed, int n) {
int count=0;
flowerbed.insert(flowerbed.begin(),0);//在flowerbed数组前面加一个元素0
flowerbed.insert(flowerbed.end(),0);//在flowerbed数组后面加一个元素0
int len=flowerbed.size();//计算数组长度,需放在加列表元素后,若放在前面则下方循环条件应该更改为 *ifor(int i=1;i-1;i++){
if(flowerbed[i-1]==0&&flowerbed[i+1]==0&&flowerbed[i]==0){
count++; //计数器自累加
flowerbed[i]=1; //将可种植位置刷新为已种植,方便下一次窗口滑动
}
}
if(count>=n){
return true;//可种植位置数量大于希望得到的位置
}
return false;
}
};
7. 题目832. 翻转图像(难度:简单)Oct.27
刷题请点击或见附录:832. 翻转图像[10]
题目要求:给定一个二进制矩阵 A,我们想先水平翻转图像,然后反转图像并返回结果。
水平翻转图片就是将图片的每一行都进行翻转,即逆序。例如,水平翻转 [1, 1, 0] 的结果是 [0, 1, 1]。
反转图片的意思是图片中的 0 全部被 1 替换, 1 全部被 0 替换。例如,反转 [0, 1, 1] 的结果是 [1, 0, 0]。
示例 1:
输入: [[1,1,0],[1,0,1],[0,0,0]]
输出: [[1,0,0],[0,1,0],[1,1,1]]
解释: 首先翻转每一行: [[0,1,1],[1,0,1],[0,0,0]];然后反转图片: [[1,0,0],[0,1,0],[1,1,1]]
示例 2:
输入: [[1,1,0,0],[1,0,0,1],[0,1,1,1],[1,0,1,0]]
输出: [[1,1,0,0],[0,1,1,0],[0,0,0,1],[1,0,1,0]]
解释: 首先翻转每一行: [[0,0,1,1],[1,0,0,1],[1,1,1,0],[0,1,0,1]];然后反转图片: [[1,1,0,0],[0,1,1,0],[0,0,0,1],[1,0,1,0]]
7.1 解题思路
- 先使用函数reverse对每一个内部数组,做一个水平翻转
- 由于只有数据 0与 1 这里当做反转时,我的办法是做位运算,即做一次 ! 。
7.2 代码
- python 3 代码
#与C++类似,但是这里要注意Python中的非操作返回值是False或者True所以不能用非操作~~
class Solution:
def flipAndInvertImage(self, A: List[List[int]]) -> List[List[int]]:
for i in range (0,len(A)):
A[i]=list(reversed(A[i]))
for j in range (0,len(A[0])):
if(A[i][j]==1):
A[i][j]=0
else:
A[i][j]=1
return A
- C++ 代码
class Solution {
public:
vector<vector<int>> flipAndInvertImage(vector<vector<int>>& A) {
int lenA1=A.size();
int lenA11=A[0].size();
for (int i=0;i reverse(A[i].begin(),A[i].end());//水平翻转内部数组
for (int j=0;j A[i][j]=!A[i][j];//对翻转后的每个数组的元素做非操作
}
}
return A;
}
};
Ps:这周的任务难度都相对简单,入门的数组基础题目,我们将在下面几周慢慢的加深难度!基础也很重要啊!加油啦~~
参考资料
[1]Leetcode网站: https://leetcode-cn.com/
[2]以上文字描述均来自 LeetCode数组模块: https://leetcode-cn.com/tag/array/
[3]刷题请点击或见附录:面试题 17.10. 主要元素: https://leetcode-cn.com/problems/find-majority-element-lcci/
[4]刷题请点击或见附录:1588. 所有奇数长度子数组的和: https://leetcode-cn.com/problems/sum-of-all-odd-length-subarrays/
[5]刷题请点击或见附录:628. 三个数的最大乘积: https://leetcode-cn.com/problems/maximum-product-of-three-numbers/
[6]刷题请点击或见附录:1550. 存在连续三个奇数的数组: https://leetcode-cn.com/problems/three-consecutive-odds/
[7]刷题请点击或见附录:219. 存在重复元素 II: https://leetcode-cn.com/problems/contains-duplicate-ii/
[8]刷题请点击或见附录:605. 种花问题: https://leetcode-cn.com/problems/can-place-flowers/
[9]卷积(Convolution): https://www.zhihu.com/question/22298352
[10]刷题请点击或见附录:832. 翻转图像: https://leetcode-cn.com/problems/flipping-an-image/
- END -