1 //
2 // Created by keyter on 2020/12/23.
3 //
4
5 #ifndef CONTINUOUSSUBTABLESFIND_SEQLIST_H
6 #define CONTINUOUSSUBTABLESFIND_SEQLIST_H
7 #include <stdio.h>
8 #include <stdlib.h>
9
10 /*此处是顺序线性表数据结构定义*/
11 typedef int DataType;
12 struct seqList
13 {//有3个数据成员
14 int MAXNUM;//用于记录顺序线性表中能存放的最大元素个数的 整型 MAXNUM
15 int curNum;//用于存放顺序线性表中数据元素的个数 整型 curNum
16 DataType *element;//用于存放顺序线性表数据元素的连续空间的起始地址
17 };
18
19 typedef struct seqList *PseqList;
20 int binarySearch(PseqList plist,int target, int *pos, bool lower);
21 void searchRange(PseqList plist,int target, int *pos);
22 /*创建空的顺序线性表,能存放的最大元素个数为 m*/
23 PseqList createNullList_seq(int m)
24 { //若m=0,则返回NULL
25 PseqList plist = (struct seqList *)malloc(sizeof(struct seqList));
26 if(plist == NULL) return NULL; //分配空间失败
27 plist->MAXNUM = m ;
28 plist->curNum = 0;
29 plist->element = (DataType *)malloc(sizeof(DataType)*m);
30 if(plist->element == NULL)
31 {
32 free(plist);
33 return NULL;
34 }
35 return plist;
36 }
37
38
39
40 /*在线性表表尾插入数据元素,返回值0表示插入失败,返回值1表示在表尾插入成功*/
41 int insertP_tail(PseqList plist , int x)
42 {
43 if(plist->curNum == plist->MAXNUM) //若表满,则无法插入
44 {
45 printf("list if full !");
46 return 0;
47 }
48 plist->element[plist->curNum] = x ;
49 plist->curNum++;
50 return 1;
51
52 }
53
54 /*回收线性表占用的空间*/
55 int destroyList_seq(PseqList plist)
56 {
57 //返回值为销毁的线性表中现有数据元素的个数,若待销毁的线性表不存在,则返回0
58 if(plist == NULL) return 0;
59 int m = plist->curNum;
60 free(plist->element);
61 free(plist);
62 return m;
63
64 }
65
66 void printList_seq(PseqList plist)
67 {//逐个输出线性表的元素,相邻的两个数据元素之间以一个空格为分隔符隔开
68 for(int i=0;i<plist->curNum;i++)
69 printf("%d ",plist->element[i]);
70 }
71
72 //第一关:求顺序线性表中连续子表(最少有一个元素)的最大和并输出
73 int seqMaxSum(PseqList plist)
74 {
75 if (plist==NULL)return 0;
76 int curSum=plist->element[0];
77 int max=plist->element[0];
78 for (int i = 1; i < plist->curNum; ++i) {
79 if (curSum < 0)
80 {
81 curSum=plist->element[i];
82 }else
83 {
84 curSum += plist->element[i];
85 }
86 if (curSum > max)
87 {
88 max=curSum;
89 }
90 }
91 return max;
92 }
93
94 //第二关:寻找线性表中没有出现的最小的正整数
95 int findMinNumber(PseqList plist)
96 {//hashTable
97 /*对于「前言」中提到的第一种做法:
98
99 我们可以将数组所有的数放入哈希表,随后从 11 开始依次枚举正整数,并判断其是否在哈希表中。
100
101 仔细想一想,我们为什么要使用哈希表?这是因为哈希表是一个可以支持快速查找的数据结构:给定一个元素,我们可以在 O(1)O(1) 的时间查找该元素是否在哈希表中。因此,我们可以考虑将给定的数组设计成哈希表的「替代产品」。
102
103 实际上,对于一个长度为 NN 的数组,其中没有出现的最小正整数只能在 [1, N+1][1,N+1] 中。这是因为如果 [1, N][1,N] 都出现了,那么答案是 N+1N+1,否则答案是 [1, N][1,N] 中没有出现的最小正整数。这样一来,我们将所有在 [1, N][1,N] 范围内的数放入哈希表,也可以得到最终的答案。而给定的数组恰好长度为 NN,这让我们有了一种将数组设计成哈希表的思路:
104
105 我们对数组进行遍历,对于遍历到的数 xx,如果它在 [1, N][1,N] 的范围内,那么就将数组中的第 x-1x−1 个位置(注意:数组下标从 00 开始)打上「标记」。在遍历结束之后,如果所有的位置都被打上了标记,那么答案是 N+1N+1,否则答案是最小的没有打上标记的位置加 11。
106
107 那么如何设计这个「标记」呢?由于数组中的数没有任何限制,因此这并不是一件容易的事情。但我们可以继续利用上面的提到的性质:由于我们只在意 [1, N][1,N] 中的数,因此我们可以先对数组进行遍历,把不在 [1, N][1,N] 范围内的数修改成任意一个大于 NN 的数(例如 N+1N+1)。这样一来,数组中的所有数就都是正数了,因此我们就可以将「标记」表示为「负号」。算法的流程如下:
108
109 我们将数组中所有小于等于 00 的数修改为 N+1N+1;
110
111 我们遍历数组中的每一个数 xx,它可能已经被打了标记,因此原本对应的数为 |x|∣x∣,其中 |\,|∣∣ 为绝对值符号。如果 |x| in [1, N]∣x∣∈[1,N],那么我们给数组中的第 |x| - 1∣x∣−1 个位置的数添加一个负号。注意如果它已经有负号,不需要重复添加;
112
113 在遍历完成之后,如果数组中的每一个数都是负数,那么答案是 N+1N+1,否则答案是第一个正数的位置加 11。
114
115 作者:LeetCode-Solution
116 链接:https://leetcode-cn.com/problems/first-missing-positive/solution/que-shi-de-di-yi-ge-zheng-shu-by-leetcode-solution/
117 来源:力扣(LeetCode)
118 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。*/
119 //若线性表为空,则返回0
120 if (plist==NULL)return 0;
121 for (int i = 0; i < plist->curNum; ++i) {
122 if (plist->element[i] <= 0)
123 {
124 plist->element[i] = plist->curNum + 1;
125 }
126 }
127 for (int i = 0; i < plist->curNum; ++i) {
128 int num = abs(plist->element[i]);
129 if (num <= plist->curNum)
130 {
131 plist->element[num - 1] = -abs(plist->element[num - 1]);
132 }
133 }
134 for (int i = 0; i < plist->curNum; ++i) {
135 if (plist->element[i] > 0)
136 {
137 return i + 1;
138 }
139
140 }
141 return plist->curNum + 1;
142 }
143
144 //第三关:找出给定目标值target在有序线性表中出现的起始位置和结束位置
145 void findPos(PseqList plist,int target, int *pos)
146 {
147 //起始位置放在pos[0], 结束位置放在pos[1]
148 searchRange( plist, target, pos);
149
150 }
151
152
153
154
155 int binarySearch(PseqList plist,int target, int *pos, bool lower)
156 {
157 int begin = 0;
158 int end = plist->curNum - 1;
159 int ans = plist->curNum;
160 while (begin <= end)
161 {
162 int mid = (begin+ end ) / 2;
163 if (plist->element[mid] > target || (lower && plist->element[mid] >= target))
164 {
165 end = mid - 1;
166 ans = mid;
167 }else
168 {
169 begin = mid + 1;
170 }
171 }
172 return ans;
173
174 }
175 void searchRange(PseqList plist,int target, int *pos)
176 {
177 int leftIdx = binarySearch(plist,target,pos, true);
178 int rightIdx = binarySearch(plist,target,pos, false) - 1;
179
180 if (leftIdx <= rightIdx && rightIdx < plist->curNum && plist->element[leftIdx] == target && plist->element[rightIdx] == target) {
181 pos[0] = leftIdx, pos[1] = rightIdx;
182 return;
183 }
184 pos[0] = -1, pos[1] = -1;
185
186 }
187
188
189 #endif //CONTINUOUSSUBTABLESFIND_SEQLIST_H