- 组队学习详情:https://github.com/datawhalechina/team-learning/blob/master/数据结构与算法(上)/学习任务.md
1. 数组定义
- 数组是一种线性数据结构,用连续的存储空间存储相同类型数据
- 线性表:数组、链表、队列、栈 非线性表:树、图
- 连续的内存空间、相同的数据,所以数组可以随机访问;但对数组进行删除、插入时,为了保证数组的连续性,就要做大量的数据搬移工作
2. 数组与链表区别
- 数组是顺序的存储结构,链表是链式的存储结构
- 链表的插入删除元素相对数组较为简单,不需要移动元素,且较为容易实现长度扩充,但是寻找某个元素较为困难。
- 数组插入数据和删除数据效率低,插入数据时,这个位置后面的数据在内存中都要向后移。删除数据时,这个数据后面的数据都要往前移动。
- 随机读取效率很高。因为数组是连续的,知道每一个数据的内存地址,可以直接找到给地址的数据。
- 在内存中,数组是一块连续的区域
3. 为什么数组要从 0 开始编号,而不是从 1 开始呢
- 从偏移角度理解 a[0]
- 为什么循环要写成for(int i = 0;i<3;i++)而不是for(int i = 0;i<=2;i++)? 留一个问题
练习部分
以下代码为C & python 版本
1 利用动态数组解决数据存放问题
编写一段代码,要求输入一个整数N,用动态数组A来存放2~N之间所有5或7的倍数,输出该数组。
示例
输入:N=100
输入:
N = 100
输出:
5 7 10 14 15 20 21 25 28 30 35 40 42 45 49 50 55 56 60 63 65 70 75 77 80 84 85 90 91 95 98 100
代码C语言:
#include <stdio.h>
#include <stdlib.h>
int main() {
int n,i,length=0;
int *array;
array=0;
printf("input N:");
scanf("%d",&n);
for (i = 1; i <=n; i++)
{
if (!(i%5)||!(i%7))
{
if (!array){
array = (int*)malloc(sizeof(int));
length+=1;
*array = i;
}else{
array = (int*)realloc(array,(length+1)*sizeof(int));
length+=1;
*(array+length-1) = i;
}
}
}
for ( i = 0; i < length; i++)
{
printf("%d ",*(array+i));
}
free(array);
while(1);
return 0;
}
python版本:
a = int(input("N="))
b = [None if a < 5 else i for i in range(5, a+1, 5)] # 真 if 条件 else 。。 用i for i in range(根据已有列表,高效创建新列表的方式。) 速度比 for i in range 快
c = [None if a < 7 else i for i in range(7, a+1, 7)]
d = list(set(b+c)) #set() 函数创建一个无序不重复元素集,可进行关系测试,删除重复数据,还可以计算交集、差集、并集等
for i in d:
print(i,end=" ") #用空格隔开
java版本:
package array;
import java.util.Arrays;
import java.util.Scanner;
public class dynamic {
public static void main(String[] args) {
while (true) {
System.out.print("是否运行程序Y/N:");
Scanner YY = new Scanner(System.in);
String S = YY.next();
if(S.charAt(0)=='Y'){
System.out.print("请输入一个数字:");
Scanner in = new Scanner(System.in);
int N = in.nextInt();
int j = 0;
int[] array1 = new int[5];
for (int i = 2; i <= N; i++) {
if (i % 5 == 0 || i % 7 == 0) {
array1[j] = i;
j++;
}
if (j == array1.length)
array1 = Arrays.copyOf(array1, array1.length + 10);
}
for (int temp : array1) {
if (temp != 0)
System.out.print(temp + "\t");
}
System.out.println("");
}
else if(S.charAt(0)=='N') break;
else
System.out.println("请输入正确的字母");
}
}
}
2. 托普利茨矩阵问题
如果一个矩阵的每一方向由左上到右下的对角线上具有相同元素,那么这个矩阵是托普利茨矩阵。
给定一个M x N的矩阵,当且仅当它是托普利茨矩阵时返回True。
示例:
输入:
matrix = [
[1,2,3,4],
[5,1,2,3],
[9,5,1,2]
输出:True
解释:
在上述矩阵中, 其对角线为: “[9]”, “[5, 5]”, “[1, 1, 1]”, “[2, 2, 2]”, “[3, 3]”, “[4]”。 各条对角线上的所有元素均相同, 因此答案是True。
代码c语言:
#include <stdio.h>
#include <stdlib.h>
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
int main() {
int flag=0;
int m,n,i,j=0,k=0,length=0;
int *array;
array = (int*)malloc(sizeof(int));
printf("Input Matrix:");
printf("Input M:");
scanf("%d",&m);
printf("Input N:");
scanf("%d",&n);
for (i = 0; i <m*n; i++)
{
printf("current:%d ,total: %d Input data:",i+1,m*n);
scanf("%d",(array+length));
++length;
array = (int*)realloc(array,(length+1)*sizeof(int));
}
printf("Matrix:\r\n");//输出数组
for ( i = 0; i < n; i++)
{
for ( j = i*m; j < (i+1)*m; j++)
{
printf("%d ",*(array+j));
}
printf("\r\n");
}
printf("----------------------------\r\n");
for ( i = 0; i < n-1; i++)
{
for ( j = i*m; j < (i+1)*m-1; j++)
{
if (j+m+1<m*n)
{
printf("%d ",*(array+j));
printf("compare to:%d \r\n",*(array+j+m+1));
if (*(array+j)!=*(array+j+m+1))
{
flag = 1;
}
}
}
}
if (flag)printf("False");
else printf("True");
free(array);
while(1);
return 0;
}
python语言:
#遍历数组,判断每一个元素和它右下方元素(行数和列数均加一)是否相等
#每一行最后一个元素以及最后一行元素无需比较(已经比较过了)
#所以遍历时,行数和列数都要减1
class Solution(object):
def isMarix(matrix):
for i in range(len(matrix) - 1):
if not matrix[i][:-1] == matrix[i+1][1:]: #使用列表的时候,如果你想区分x==[]和x==None两种情况的话, 此时if not x:将会出现问题:
return False #使用if not x这种写法的前提是:必须清楚x等于None, False, 空字符串"", 0, 空列表[], 空字典{}, 空元组()时对你的判断没有影响才行
return True
3.三数之和
给定一个包含 n 个整数的数组nums,判断nums中是否存在三个元素a,b,c,使得a + b + c = 0?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
最后一题C太耗时,还没写出来,答案仅供参考
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
算法流程:
特判,对于数组长度 n,如果数组为 null 或者数组长度小于 3,返回 []。
对数组进行排序。
遍历排序后数组:
若 nums[i]>0:因为已经排序好,所以后面不可能有三个数加和等于 0,直接返回结果。
对于重复元素:跳过,避免出现重复解
令左指针 L=i+1,右指针 R=n−1,当 L<R时,执行循环:
当nums[i]+nums[L]+nums[R]==0,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 L,RL,RL,R 移到下一位置,寻找新的解
若和大于0,说明 nums[R] 太大,R 左移
若和小于0,说明 nums[L] 太小,L 右移
---
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
# 存储结果列表
res_list = []
# 对nums列表进行排序,无返回值,排序直接改变nums顺序
nums.sort()
for i in range(len(nums)):
# 如果排序后第一个数都大于0,则跳出循环,不可能有为0的三数之和
if nums[i] > 0:
break
# 排序后相邻两数如果相等,则跳出当前循环继续下一次循环,相同的数只需要计算一次
if i > 0 and nums[i] == nums[i-1]:
continue
# 记录i的下一个位置
j = i + 1
# 最后一个元素的位置
k = len(nums) - 1
while j < k:
# 判断三数之和是否为0
if nums[j] + nums[k] == -nums[i]:
# 把结果加入数组中
res_list.append([nums[i], nums[j], nums[k]])
# 判断j相邻元素是否相等,有的话跳过这个
while j < k and nums[j] == nums[j+1]: j += 1
# 判断后面k的相邻元素是否相等,是的话跳过
while j < k and nums[k] == nums[k-1]: k -= 1
# 没有相等则j+1,k-1,缩小范围
j += 1
k -= 1
# 小于-nums[i]的话还能往后取
elif nums[j] + nums[k] < -nums[i]:
j += 1
else:
k -= 1
return res_list
if __name__ == '__main__':
s = Solution()
result_list = s.threeSum([-1, 0, 1, 2, -1, -4])
print(result_list)
来源:CSDN
作者:Arrow7TT
链接:https://blog.csdn.net/Arrow7TT/article/details/103866817