数学建模社区-数学中国
标题:
数据结构之数组练习
[打印本页]
作者:
杨利霞
时间:
2022-9-8 09:59
标题:
数据结构之数组练习
数据结构之数组练习
( t8 Y2 r1 ?1 F5 `
1.leetcode704
: b7 K( x; n0 K# c3 b- T+ i! Y
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
3 M/ V* p' H, n, ~8 c
' R2 j: `) K# E5 x" H. j. H/ I
题解:升序 数组
( l* e$ L- B3 m1 U7 r" D" ?
; ~: C1 N1 X9 Z Q
方法: 二分法
/ G$ u" h% ?$ Q! o) M" Q
6 E8 k w6 a6 y" i. X6 P
思想:定义查找范围[left,right],初始查找范围为mid((left+right)/2)
. Y3 c& |/ u1 [$ w" M4 d) M4 U) ?
+ L/ \0 D* P6 _( t: O( X Y
比较nums[mid]和target的值:
9 K* f& ^8 \; i- [
( E h% w& @% |+ B C$ J5 V0 [8 p
如果nums
=target,则下标i即为要寻找的下标;
; b& q2 C& Z0 E& ], k
$ B) o) W- M! x+ C2 O
如果nums[列]> target,则target 只可能在下标i的左侧;
; q5 \1 s1 u/ R6 b# B% O
6 h& c4 Q; A+ Y. ]
class Solution {
0 n, H m0 J9 F" L# O% e a
public:
* J6 H! l; H* H7 V! A) a
int search(vector<int>& nums, int target) {
" e/ W8 F7 W/ l& `( Y; y6 q! c! p
//区间[left rigth]
' u! g K# q' i' M
int left=0;
* p: j( E5 v' Z0 J- b: ]) d7 G
int right=nums.size()-1;
, n; V% E! g! @% _
//结束条件 left>rigth
: Q/ g5 t( i7 T+ z2 s4 M# ?
while(left<=right)
4 a4 s2 K! q/ X
{
" d! x$ K+ F8 |/ U( Q5 [
int middle=left+((right-left)/2);//始终保证 有变量 [left,middle]或[middle rigth]
* A" F5 ]% Z w: C7 k! ^" @# t' u b
//[middle+1 right]
8 }) V( C* c6 n/ u% x
if(nums[middle]<target)
1 K4 I+ Y z% w- T5 m: v7 y
{
2 O% }$ m1 b( O2 Y0 T0 L0 d2 q/ X
left=middle+1;
. w2 h9 }: _! I |! |/ `
}
0 N! A: v& i" [+ c6 @& Z
//[left middle-1]
. d5 y! G) y) n2 a q% Q
else if(nums[middle]>target)
/ j j' [0 y7 @6 O- r0 n
{
) K7 X q7 f1 X
right=middle-1;
( k$ q8 O9 m- V; g! m' ^
}
1 O$ R; m' _; s# b. F
else{
; A! w/ C- K y: x$ c
return middle;
$ h+ Z! a. G0 }9 S* u" Q
}
# ^1 b; v" s3 O }! @( U
0 q& M* M* u- S- C) c
}
A% m: u& J0 s
return -1;
1 x# }# i- A. D9 r1 H) g, p. \' N
/ ~: z5 T: r0 m; D
}
/ C1 E* @+ a" w" c+ G; v
};
0 C; l5 H$ E! S$ N9 g/ l/ V: f3 |
" v9 g; G/ _! Q i5 b
注意:
: H: T6 A" r- E4 v. N
% {$ Z. h# C# u9 [# o5 i
(1)设立区间为[left, right],终止条件为left>rigth
! ~: G! L* O8 a( w7 s; M5 w% f8 L
(2) (left + right)/2==int middle = left + ((right - left) / 2)
8 ~6 ]% J* Q3 G( j" X4 ^ c5 {1 w
(3) 通过改变区间的左右值;复杂度logn
& |6 y. H0 w) X, A
- a5 D* \& h: v' }. B- S
2.leetcode 27移除元素
9 _; }8 A& ?6 S
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
$ N$ a0 E$ s! b2 Z1 T0 P
0 m% M# D$ k4 b0 m
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
3 C ^3 \% `& d& ]2 g
{6 h9 l" k. c* w( V
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
1 A! Q8 b( u( R' r( V' G( j
& U) ^( H5 O. X8 r- D
示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。
! I3 u- k' _; B/ c v$ G
; T( V3 ], M; _- w/ @
示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
3 _5 h E. F( o" H: ?
y+ u/ o6 i) |8 o# b
思路:要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。
* ~/ ?. l, t* W
2 `- `7 B2 H+ q9 O9 d" D; \
方法:双指针
% M. }2 m# m. [' _% M
( l' Z2 | X+ r8 L+ Z) B+ y
class Solution {
8 t0 {: J& P% L4 W4 A6 i
public:
( R0 D, K! R; r
int removeElement(vector<int>& nums, int val) {
% B9 `! m5 e, e" i. B
int solwIndex=0;
0 @9 V% x8 U1 w0 Z5 i
for(int fastIndex=0;fastIndex!=nums.size();fastIndex++)
/ ?0 R: s4 u0 n8 d7 H- t: h
{
8 D+ L" ?* x% N+ M' V
if(nums[fastIndex]!=val)
( l/ p2 j3 s1 C$ Q( z7 C9 h' r
{
8 X5 [. a b5 D' f1 w
nums[solwIndex++]=nums[fastIndex];
" R- L; }2 y9 t; ?' l! R
}
, A# Y( H C. [) m
}
K( O4 H \5 t: K
return solwIndex;
& P6 _! n3 b: X+ ~1 G. t1 K! K
}
, g- G& z* [! T" p; b7 ^
};
) S0 `* v) q# `6 J0 p* L% n
solwindex:用来覆盖
7 s- K3 W: K+ E; Z$ z
: [% k" D% S. Q; x5 Q7 f
fastindex:来找删除元素++
2 l: U# N! _8 M) ]2 J
8 b. ^0 X+ V" T) a( X6 T
3.有序数组的平方
8 ^4 n& U7 P& K, J* `# Z
给你一个按 非递减顺序 排序的整数数组 A,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
3 n5 Y$ k: ~, v8 A3 L) A
+ B1 z4 p( _* v) G' e" B( \! T
数组其实是有序的, 只不过负数平方之后可能成为最大数了。
7 X* F o' m* |) N( f
" C1 W/ }& r8 B5 D+ \
那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
! `* v" c* |4 G# W
* q+ E9 J) g- q- Z- x& r
此时可以考虑双指针法了,
& I1 G/ y5 {3 P6 U
' f- Z$ Y5 S! v* R2 w! [
i指向起始位置(负数),j指向终止位置(正数)。
5 G5 q5 {/ T# J( _4 ~
9 _* _) o, U2 @1 Y1 [. ^& Y
定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。
2 z P' p3 P% n1 A, O8 W1 U
# C0 x# Q& U- [/ `7 L
如果A
* A
< A[j] * A[j] 那么result[k--] = A[j] * A[j]; 。
6 d, w( Z [$ L r/ ?& f: F
$ v! Y: x9 r, g6 P
如果A
* A
>= A[j] * A[j] 那么result[k--] = A
* A
;
; b. a g" I5 D5 s# H+ [
! v* C5 V7 `! `! y: b! g r0 u$ K, u
class Solution {
+ w" W% G. B U5 m
public:
8 L& p8 ^7 o5 A; n; X
vector<int> sortedSquares(vector<int>& A) {
) a1 l& Q3 z2 q
int k=A.size()-1;
3 V2 Y2 f, m( F/ T: y) Z' x3 ^3 y
vector<int> result(A.size(),0);
; y( }, m( N: W, G) x3 k) _
for(int i=0,j=A.size()-1;i<=j;)
1 L" ^! \1 P4 O8 w: _3 {0 y
{
9 ~# c5 f2 x. T' v% b) I
//遍历一遍
: m2 O. ]) ^2 t8 M. j( O
if(A
*A
<A[j]*A[j])
/ X: x% [( e& P' `1 G
{
0 r' k/ I! z# R1 R Z# a0 [ _
result[k--]=A[j]*A[j];
+ z5 L$ o. B$ ?
j--;
' G2 i2 U- o1 @* z) E/ d" M
}
5 M6 `& r M$ r/ P- c# J
else
% I: w# f# h( I$ |
{
! ~3 L' q4 {5 ] ~/ M
result[k--]=A
*A
;
: Y+ }7 n1 r" w; A' A4 \
i++;
. U6 Q0 B7 C$ y/ h5 ~; c
}
0 C$ B; ]! y- d" D
}
2 Q$ S6 x, ]3 u) j& i9 \9 D: \) E
return result;
' X, m0 ^2 l" b4 }2 c2 D2 I# h
" D; | q+ Z) u+ T5 \$ ` U1 \
}
# K5 a9 D; W E% |& V- }9 ?
};
! u. A: w7 \& `; p6 l% H
0 K3 O/ c' f( d i
4.长度最小的子数组
; ]( F0 c! C3 c, z3 G) p
给定一个含有 n 个正整数的数组和一个正整数 target 。
" ?% E3 ~, x* p' F+ m9 C! ^0 y
, A- V* |) l# k% O5 [. S
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
7 ?8 Y$ [% d$ H w0 k
* F K% Q; ]9 i3 M8 R) B. |
方法:滑动窗口法
1 z8 R9 w% u: t3 }% Z
1 a) e# v; m6 X7 O+ k
就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
8 E8 u! w* @, j$ c8 u* i( M$ t
. X) l" l6 [" ~: M1 ^3 W
三点重要:
* B2 o* V/ ?$ N; s) n; H/ d" Q l
) |* [2 L+ n, V+ B" U3 J2 x0 i0 \
窗口内是什么?
# I2 ?) Q* t1 H, k* R N {7 |8 s( Z
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
$ N5 T: B$ r. ?
如何移动窗口的起始位置?
5 G3 A1 ^, {' W; f6 P' o5 S \
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了
$ |/ `4 c& D v, Q+ p7 @# m
如何移动窗口的结束位置?
+ m( ?1 n0 F' D3 s% `. x
窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
$ R0 T$ z/ z( f8 i7 @; ]
. E& P- C$ }, v8 g8 G8 b2 n
代码如下
8 E2 H. I$ X. I/ v1 Z3 [# c
( R$ u4 [, p0 E7 |
class Solution {
- U7 t2 s/ i5 X& P" o" G+ h9 \
public:
- E! w5 E+ v+ p3 [1 `
int minSubArrayLen(int s, vector<int>& nums) {
: W% r, h% h! O ~: ^0 i( O$ N: t$ a
int result = INT32_MAX;
8 [: N5 `1 Y8 ^) M
int sum = 0; // 滑动窗口数值之和
- o4 D4 j# Q' y: z0 `
int i = 0; // 滑动窗口起始位置
- y7 u2 w$ A! b! X6 m' l* c
int subLength = 0; // 滑动窗口的长度
! g9 D' `; N/ K: ~
for (int j = 0; j < nums.size(); j++) {
2 ~7 b+ a: r) `2 ]# m- y) G$ ~
sum += nums[j];
) H* b9 a$ j- I w( B) ^5 A- S
// 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
) s, ^! B; n. f4 `
while (sum >= s) {
; Y% M! u* e- @/ P; U) C
subLength = (j - i + 1); // 取子序列的长度
+ I8 |* W: v1 I& z! u Q3 Y
result = result < subLength ? result : subLength;//一定会赋值
: L5 A& G; k- s# Q0 @8 |$ @8 m$ \
sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
4 h/ {: l0 c( a; X) N- @
}
+ b$ Y/ g+ P2 H+ u
}
, r1 j! h' v5 X; a. w2 U0 [4 f
// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
" a: X/ T; C+ J8 w5 c, ^# Z
return result == INT32_MAX ? 0 : result;
' a7 o% H" z9 S- H1 j
}
* z( ~, {# o$ ^: l+ x
};
, a7 O/ p# V" b: R+ |
/ }- n2 K Z! \% p9 d
一旦大于,就减去左区间的值
) a( g( |. Q. x
# j# @3 o" M6 G8 b8 f
5.最难题螺旋矩阵||
b+ n9 O7 D( t0 c
模拟顺时针画矩阵的过程:
g" s1 t1 {' w7 p
6 H/ O9 V$ F' i% _6 r+ N
填充上行从左到右
9 Q0 h: V, ~6 }
填充右列从上到下
+ ?( ]9 x2 U7 p4 s. H6 M
填充下行从右到左
6 w8 R; n2 g) V% R' Q0 G9 Y) C
填充左列从下到上
" c! {) M ]7 i& ]% D1 G
由外向内一圈一圈这么画下去。
, I. @- h- ]' k! |2 F
' W. k- |) x8 C9 x# t) i9 b, ^
这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。
8 e7 _8 J5 |$ R6 \0 ?, k, B2 m) ^, ]
1 `0 f, I. L( O
# ?1 H9 C5 l( S; J3 ]
- m+ y9 g* n+ B
5 d! u2 W9 h' L# o+ O
' {7 r% J9 f( R
class Solution {
8 _: A1 z$ c, D C& W' a. s$ k
public:
* h, U, G9 C ^% c: E" f9 A( `
vector<vector<int>> generateMatrix(int n) {
/ F/ ]1 c0 S8 m% n# l3 X9 B
vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
* i2 f* g7 C2 h& i
int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
$ g: x! j0 i3 P6 S0 n: S- }4 S+ c
int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
* ^' e9 X A5 h2 \- C2 O0 l4 p! F
int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
1 J2 F* c2 o( _0 A. W" H5 B8 G% s, r
int count = 1; // 用来给矩阵中每一个空格赋值
5 `4 s) m; P- U5 c. x) R1 {" Q
int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
+ c; F6 U; s( M
int i,j;
. z. ?" E3 s$ I7 M4 [' [
while (loop --) {
, b1 {7 h: C6 m& X g! l1 B: p
i = startx;
% Z) Q. d' U5 r) ]7 h9 G
j = starty;
2 D" p a; y1 u0 Z& @. r8 N
7 x) f6 B [( e
// 下面开始的四个for就是模拟转了一圈
& s. B3 ], R& r, F7 P$ w2 Y
// 模拟填充上行从左到右(左闭右开)
0 ]# e$ P2 \/ @6 {
for (j = starty; j < n - offset; j++) {
, I0 x8 Z/ P0 U9 ~9 U
res[startx][j] = count++;
$ N8 t, h# u7 t& A4 N( b
}
# m- ~, @0 p) O9 W! G
// 模拟填充右列从上到下(左闭右开)
; X: b/ g1 S" ?4 h; L" t
for (i = startx; i < n - offset; i++) {
/ ?. v4 f) G1 X* D }0 a/ {
res
[j] = count++;
* Y& V4 p8 c( J5 Y& U3 g) O: v1 m
}
7 y7 W/ i+ Y6 y- q3 v
// 模拟填充下行从右到左(左闭右开)
6 z3 y7 r& T8 b4 N
for (; j > starty; j--) {
* ?5 N" u7 c# i. l! Z
res
[j] = count++;
9 j9 T! W$ J$ c
}
$ ^& u8 e& H" w, e0 l2 Q" T% }
// 模拟填充左列从下到上(左闭右开)
; _) T( P5 x+ E n n: h0 C
for (; i > startx; i--) {
9 I) Y4 b( ^6 j! D5 i" d- I+ H
res
[j] = count++;
% B4 H- [- a6 g/ Q
}
) v* F: J2 Y* |1 O
7 T1 y4 n. V3 L: l
// 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
5 v+ `+ W2 h, l( b) P
startx++;
8 u4 o: A' e# }
starty++;
) A% r( }" _2 [% e) d! [+ a
" |, G( ^8 w0 d6 V, ~' p' m
// offset 控制每一圈里每一条边遍历的长度
/ x6 e* G- A& ]! q' M _9 S, ?
offset += 1;
( e3 P% T: v" t0 n7 C
}
; h# Z; C3 _. R% p* K
) C5 I/ o! g4 C
// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
" E4 o( L$ m" C- w
if (n % 2) {
" ~! N& J( m1 X: U" T' B6 B
res[mid][mid] = count;
. P! @, g* x4 Q7 {# e
}
5 W* {/ J! v: E6 _0 ~, C
return res;
1 q/ d$ x" R- |1 b% }
}
5 L# Y& A1 f0 [% u. _- w
};
3 o- V" a3 Y, |# z) p1 |) Y; X
" S9 j4 }4 y+ v6 L2 r! e
————————————————
& }( A6 F5 d9 `, O1 |
版权声明:本文为CSDN博主「编程界的谢菲尔德」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
) ]; R2 J1 Y4 h& V
原文链接:https://blog.csdn.net/qq_62309585/article/details/126745039
( \$ h2 J: a; Z: z- ]( j( q
. T/ J& e# @7 w9 w( w) O5 [
7 U+ n1 I5 A: G% X
欢迎光临 数学建模社区-数学中国 (http://www.madio.net/)
Powered by Discuz! X2.5