数学建模社区-数学中国
标题:
数据结构之数组练习
[打印本页]
作者:
杨利霞
时间:
2022-9-8 09:59
标题:
数据结构之数组练习
数据结构之数组练习
0 h% k4 Y- [% Q/ j! K- R: m0 ?0 m) {
1.leetcode704
" f% o1 e: _$ V
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
6 ?8 [2 |: R1 K, ]1 Y
1 b. e( P2 \9 d3 c% x
题解:升序 数组
/ T/ I+ W, f! ~/ r( N
; y3 H# w. m4 ?. B, k- v
方法: 二分法
/ d, b k& ?: M
5 T8 r' G {: u/ l4 [
思想:定义查找范围[left,right],初始查找范围为mid((left+right)/2)
# p' p: X7 Z3 @; a4 g5 O& F0 s
- |" k9 `6 C5 X% X1 S0 n
比较nums[mid]和target的值:
+ R9 o% t9 \ s
; c2 K4 j: T/ C( S! @. k- S/ f9 B
如果nums
=target,则下标i即为要寻找的下标;
}! Y. h( g C' v4 B; U! e2 m! `
, l8 D8 @ B. D+ H
如果nums[列]> target,则target 只可能在下标i的左侧;
% M8 s$ R z& D$ T/ P; I
# S, \3 V+ P2 v: R' c3 l* P
class Solution {
f2 X- u4 l& n0 y$ I* l4 Y4 Y
public:
6 ^' F9 b4 U' H1 T) O0 G# D" n; U
int search(vector<int>& nums, int target) {
6 d! @" K$ n$ ^$ v4 o, B4 _
//区间[left rigth]
/ Q* ^/ ~" ~8 R9 ~6 y, z2 H
int left=0;
( ~. E+ r5 t( Y2 k0 i- u$ ]
int right=nums.size()-1;
1 M6 P4 M! Y/ o2 ~, S) h2 x
//结束条件 left>rigth
+ X5 ?2 u! E! d- Q1 T
while(left<=right)
' u/ H& a, }. O. Q7 {3 n
{
* O1 `; Y4 C" q; C) y5 r. w
int middle=left+((right-left)/2);//始终保证 有变量 [left,middle]或[middle rigth]
3 q6 P7 a7 F5 A: y
//[middle+1 right]
8 Y; w7 A+ Q* _" u$ Y& e$ n
if(nums[middle]<target)
( Y# I6 m8 w4 t! H0 ^( [3 k
{
, J/ P! e: o- f8 c
left=middle+1;
+ w9 ]) ~& C: ^4 ^2 t- d
}
# Q( J t) F Z4 X' O
//[left middle-1]
3 D; ?% n5 Q, J I5 s3 r, E
else if(nums[middle]>target)
( S: s1 I7 O0 J3 n
{
+ ^3 A5 `; c' W/ n! L; g+ U
right=middle-1;
8 L( ?# @1 N ]8 U/ e1 ^
}
: M; w$ \: X* L+ r0 y% u) w
else{
+ n2 z$ \" U0 o' @' i' v& N
return middle;
+ F' I& p- W% i% g
}
7 H- a* ^+ A; A* Z0 Q
) b1 _3 V6 F8 i+ ]. F3 f5 {1 i
}
+ S* m8 R ^. E* q* r# \
return -1;
' P* f) G6 ^, K& M
9 ?. y* g$ [. X6 V
}
/ J C/ O+ b# I! C
};
; j, c4 q) I/ }9 h2 {; G1 ]
+ S9 {" O) D d! @/ D, G: [
注意:
- H, Q- @2 h' F. f9 D% ?; L
1 u- u( Y r" B' e: B! B
(1)设立区间为[left, right],终止条件为left>rigth
7 `# I& A& I0 F% n+ p
(2) (left + right)/2==int middle = left + ((right - left) / 2)
* ^, X# d! \7 e3 @. ]
(3) 通过改变区间的左右值;复杂度logn
9 l$ B0 J% e! }2 \2 f0 M) {( d8 w
; O" f& Q, O+ T2 X$ g
2.leetcode 27移除元素
) y+ f% P+ I) m+ w
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
% l+ f0 w+ ^+ ~1 l0 o6 C2 }2 u
1 p1 e' N$ O- F
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
* N4 C6 _! p$ a
6 q9 O: Q2 Q0 @: K D
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
7 z! o+ [1 G* L+ X; d' o, O
\) Q2 c3 G6 M: E- @3 g& [
示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。
+ s, k/ P* w- _0 f
' d) A: [( G7 F; y1 r; [% R
示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
. w+ a/ q/ X7 Q h
0 y$ ?* M" ]! q% @! |9 l( i! V5 ^. }( F
思路:要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。
! w+ R* Q1 M+ w0 Y
`. F* B {( g7 M8 f% |$ M
方法:双指针
) w* X$ u! {& ` y
! U- d( I* q1 F, S6 n- d( t
class Solution {
+ [5 \) `1 S2 D S/ O
public:
4 A: \% }+ w ^* z
int removeElement(vector<int>& nums, int val) {
R2 [0 O# U" @! E8 d) c! M& U5 f
int solwIndex=0;
. q+ K( x4 Q4 R$ \
for(int fastIndex=0;fastIndex!=nums.size();fastIndex++)
$ ^ T$ z8 ^5 F
{
: R# S$ O+ v3 K! r6 H
if(nums[fastIndex]!=val)
- H& H! S& |, ~: g
{
/ p n4 W( G F- U7 U0 p$ o
nums[solwIndex++]=nums[fastIndex];
' Q4 J. G+ k$ f5 V
}
+ R5 o8 d4 Y$ n+ `3 h
}
5 H" _+ H; h7 L' ~2 J; |: L! B( M
return solwIndex;
+ \8 N9 c# w( _, }
}
* ^. A8 e2 T2 R; H( `$ a
};
0 Q; e. F7 d# P8 N1 o) K6 {! M
solwindex:用来覆盖
F' B* ]; m# t( {
6 r. S; U6 b$ B- v; Z q- V
fastindex:来找删除元素++
$ U& P2 L; K( m. v, u \
) m1 J5 ~# X& S$ x* B- K
3.有序数组的平方
* I! x, p6 L% I$ r8 r: n$ I
给你一个按 非递减顺序 排序的整数数组 A,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
( \4 Y3 d7 e! `5 b$ q: |7 }: x
, P& e4 i3 y/ g2 s# i5 D
数组其实是有序的, 只不过负数平方之后可能成为最大数了。
9 Z% ?* Q; d, q5 v. z3 w
1 f9 [: k$ v+ [+ b, ?6 B
那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
3 l" J# o8 w' o4 C+ [2 V
, @! {0 f) O) b* m2 \
此时可以考虑双指针法了,
) V3 m+ q& v; W& b' l
7 q( x( Y; q2 y& E$ S+ ]9 g
i指向起始位置(负数),j指向终止位置(正数)。
+ u2 \6 F. e/ v! l- Y* K6 B5 r. M
6 k; |( M5 H! b; [8 B
定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。
! N( Q& ]9 Y2 V8 M' E6 l- n8 m9 f' `
: z6 m P5 b3 x7 K
如果A
* A
< A[j] * A[j] 那么result[k--] = A[j] * A[j]; 。
, e% r+ \( a& J& ?3 D9 R
5 M7 j6 W8 x$ y6 v! O: R
如果A
* A
>= A[j] * A[j] 那么result[k--] = A
* A
;
2 \ v) P- j! F) M
$ T4 ~/ N/ f4 R+ M% b0 O3 I. \3 u
class Solution {
7 A5 B3 i- m1 u8 Q
public:
- J$ s2 @% R/ X$ W; W
vector<int> sortedSquares(vector<int>& A) {
6 y) F8 w2 J2 @
int k=A.size()-1;
+ p1 @$ w7 f6 c* ~9 i
vector<int> result(A.size(),0);
' F3 k% h) \% h8 a1 ^4 _4 g
for(int i=0,j=A.size()-1;i<=j;)
8 {7 [1 f% U) g' t% Y; Q
{
$ I0 i. H- K2 G/ l: [
//遍历一遍
: G" N- n" [; B6 R/ n( v& j, Y
if(A
*A
<A[j]*A[j])
! c+ E) t' M1 k* J; x! I$ [
{
. o8 j" x% a; z4 ?: i( l4 t" K
result[k--]=A[j]*A[j];
& q5 ^6 B3 L8 h
j--;
) x" s" C( k: y8 T
}
* \. I" z+ o- |+ ^! n
else
- P9 ?1 E. I- j
{
% r" h$ }# b; i/ Z4 }! N @. C: v" K
result[k--]=A
*A
;
2 P7 t1 d4 q6 r* t/ |
i++;
! d) E' r4 [" m, j9 _! [
}
3 o. q7 c: c# a5 H
}
! M; y+ _" o0 D" ], g% X3 r
return result;
9 x# H% K6 P: r! Q2 x t* V
% G8 B2 E6 X' v* i2 l& g1 k& O
}
]; H& h c v1 ~
};
5 H8 e1 `7 Y* q" S) o+ D- f
% E/ k& ]+ q, d
4.长度最小的子数组
4 K0 ]3 n+ [/ _$ B v9 P o
给定一个含有 n 个正整数的数组和一个正整数 target 。
9 V: e. u' j, o/ f, W
9 I1 q( p% R. `+ f4 T. o0 T, f
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
5 J9 P0 R! h: N* X
# |2 @, ?& w* r) G
方法:滑动窗口法
( o% `. {6 L8 k Z
/ T+ D- w& `7 c J2 K
就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
) T: B' g8 N2 |( y' Z* `
! g+ x( S/ ?. g; _
三点重要:
2 Y, ~$ @# u' \
( y, `, s7 F' g% }9 w# k% T* |! P( n
窗口内是什么?
9 g( _' Y6 u, f0 ?- Z
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
3 G4 J" ^9 W3 Y' o% `
如何移动窗口的起始位置?
" ~! m3 g- Z9 |, \+ i* x0 ^
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了
2 ~ x: h/ v& l3 x% X7 X4 ]& z
如何移动窗口的结束位置?
* k7 q5 A/ c' g- ]( E
窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
$ _8 {6 K) i3 t" u, \
) Z: D1 R0 k* Z! u: h+ F
代码如下
# c" l3 |& t. @ i$ |
& b B1 b8 E, @9 `1 [; n- P
class Solution {
. J! D% p) j" ~- P: p b* H
public:
) X9 H" u, ?* A& M
int minSubArrayLen(int s, vector<int>& nums) {
- F4 \, f7 F' H x# X
int result = INT32_MAX;
?4 M3 z/ x. t/ ?( J3 H& g
int sum = 0; // 滑动窗口数值之和
* X0 M' {' ~' Q0 p
int i = 0; // 滑动窗口起始位置
m: u0 O6 O5 ^8 Q# e9 _2 i
int subLength = 0; // 滑动窗口的长度
Y8 p6 t% {1 h& ^- a
for (int j = 0; j < nums.size(); j++) {
3 o* b2 R6 a- z* {
sum += nums[j];
: E. ?9 _* v( W) [* \& v0 D
// 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
7 L2 R' h3 s$ \" Y. E1 T4 v7 m% p( N
while (sum >= s) {
+ v# I( B. _8 o: d, I
subLength = (j - i + 1); // 取子序列的长度
: O1 m* S6 R! C1 ]2 e9 o b2 G. \
result = result < subLength ? result : subLength;//一定会赋值
% B" i5 S- S! u$ M% d# D) u8 O8 S
sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
$ E9 [- p; q5 `
}
* H, C0 d( ?9 }6 e, U- J# x2 x
}
, `+ C Z+ A( g/ V, w
// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
, f, F, \; s e7 n1 ]0 L. d7 L0 Z/ w
return result == INT32_MAX ? 0 : result;
1 @; y- \: ^# B4 I; ~! o! \3 m
}
* U$ v" o# E1 `1 N" n( x
};
) C8 M0 Z9 v3 r+ I1 {
; A" @* W# y! P; M* Q
一旦大于,就减去左区间的值
4 O+ `3 {0 i& t r2 s$ C8 t
! I6 F9 c5 Z1 m% i2 z; n$ _4 `
5.最难题螺旋矩阵||
; w+ n) w. ~7 Y; U, X R4 u
模拟顺时针画矩阵的过程:
; C0 T" q4 L: y. k
3 ^$ @( x7 s; U" J; J6 B
填充上行从左到右
* L% \2 n- ^0 x) a
填充右列从上到下
. _/ `1 F2 V0 ?9 y* ^
填充下行从右到左
5 T$ e" T7 h5 r6 W$ g8 W
填充左列从下到上
% C- Q% C1 ]$ _3 ]: Q
由外向内一圈一圈这么画下去。
" g3 N: f* ~% [
6 B- N0 O4 z @( T
这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。
6 w# E0 j* X4 z! {
0 e u% D V" d0 p) T7 Q1 G
! C# s. I) m/ u
3 c8 w# V* f/ ?; o+ k! l) D) S5 V
4 z6 C& p% k% @. m6 c
( M# t* y" N: _ \9 P- Y2 F
class Solution {
2 K% h- U7 ]: y( H" D
public:
, P3 D# T* w9 u: z% Z+ m
vector<vector<int>> generateMatrix(int n) {
) G1 }9 X2 r6 E: D1 @( E& Q, e) @% [
vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
* e3 d* a6 v8 l. d% T6 D
int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
+ A% x X& l5 B5 Q& E7 d
int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
: v6 B/ o$ y7 g( s* S
int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
S2 p D+ M4 K$ E- c' ~3 H
int count = 1; // 用来给矩阵中每一个空格赋值
5 S( a9 s/ o( K2 K* ^) |" ^
int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
; T' T0 z/ d: A% D% w
int i,j;
+ ~$ O. T3 W2 y7 d- ]1 m$ e
while (loop --) {
. W8 b; z5 T& P
i = startx;
2 P1 o8 }' S6 ?
j = starty;
& y! A h; N1 `9 ^: _5 S( U$ H8 w
' Y* d0 ^5 q8 X/ _
// 下面开始的四个for就是模拟转了一圈
. Q2 Y1 u8 N% i6 H1 c2 [
// 模拟填充上行从左到右(左闭右开)
5 D: J! a0 o0 }4 u2 T+ X
for (j = starty; j < n - offset; j++) {
4 O, X$ h* ~: s/ m
res[startx][j] = count++;
$ Z! B* T) z: H
}
- T- k. F6 l0 F/ D6 t
// 模拟填充右列从上到下(左闭右开)
' G) e- b2 S8 Q G: ^
for (i = startx; i < n - offset; i++) {
o3 g( E) l4 d; | c w( ]% Y# U
res
[j] = count++;
6 `: |1 Q* B( Y- O$ u6 `
}
1 N/ g, ]0 r: C1 C
// 模拟填充下行从右到左(左闭右开)
9 c3 J4 e: n% i! {/ T$ V$ S
for (; j > starty; j--) {
3 d5 B6 a" Y. z! I/ D
res
[j] = count++;
! u# K2 `- N5 _9 m* Z8 q+ `
}
9 M7 b& J# C! e6 |) s" G8 x
// 模拟填充左列从下到上(左闭右开)
9 z7 S, g* i- f/ F* o h
for (; i > startx; i--) {
* ^# s- ?" t: q
res
[j] = count++;
9 J' W( f+ K: d. j" Q B
}
7 @" B0 Q3 b8 U9 ]- l) l0 w
1 W+ k. k! N9 x( k* u- ^$ d
// 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
* o* o+ F) B. W( z: d
startx++;
& r% i, n) L5 C% T7 K( J) @
starty++;
: _1 m/ U. F( o8 C" L
" x& `& e4 L$ S; y2 q, `$ Z
// offset 控制每一圈里每一条边遍历的长度
7 L2 n. e# p: C/ R
offset += 1;
" t1 h' A! H3 \- g8 h( ~
}
# z5 h/ u6 d1 e# h1 n$ a6 P, ]! K
6 J1 n$ Q8 g, ^" [$ b& U
// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
. \( |; n( w# a r& i) g5 `
if (n % 2) {
4 }( `, r3 J) c* j, K& I0 D3 h
res[mid][mid] = count;
; A% u4 f/ R+ ~" M; G/ H
}
% s; I7 e1 f- g, c
return res;
, t- S0 N% U9 C x! {! w4 ?/ c
}
& `. i, S+ D: n
};
3 S2 p9 [. q- j: h0 U k/ Z- F
+ o; H+ f/ K! V0 u2 V' O5 T
————————————————
3 I+ ?, Z( F) p8 \! ]
版权声明:本文为CSDN博主「编程界的谢菲尔德」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
6 } Z- y# {( R$ e3 x/ l
原文链接:https://blog.csdn.net/qq_62309585/article/details/126745039
7 M% e0 J( `$ P, r$ d
8 ^8 W' R8 b/ ]* p# j
3 p. q7 v( ?2 k/ d4 ~& X, D
欢迎光临 数学建模社区-数学中国 (http://www.madio.net/)
Powered by Discuz! X2.5