数学建模社区-数学中国
标题:
数据结构之数组练习
[打印本页]
作者:
杨利霞
时间:
2022-9-8 09:59
标题:
数据结构之数组练习
数据结构之数组练习
1 F8 q# M6 j' P* y7 q
1.leetcode704
; F! K0 a# `+ R, ~: j8 N7 e
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
2 u# R1 X2 A2 {# [
7 l; `1 n, A2 Q- Y
题解:升序 数组
* c+ Z+ u$ {5 ~* _5 z8 Z; Q. L
5 @5 K2 G! O z5 G- Y, C
方法: 二分法
7 |# y9 O1 X! S% E+ w% T
. b$ w8 A3 V: w/ ?; T& f" ?4 H5 F
思想:定义查找范围[left,right],初始查找范围为mid((left+right)/2)
; k) x- i0 @6 ]! R, q& ^
# O) l$ L7 M% A, P
比较nums[mid]和target的值:
% N$ {$ {1 s; K* A
8 m' n* f" R- ^
如果nums
=target,则下标i即为要寻找的下标;
# f3 G6 H: ^5 V# X# }
4 @0 B) W e. J; F) y8 R" g* M& V, i
如果nums[列]> target,则target 只可能在下标i的左侧;
" i k. K# g. s8 T) A
0 C9 ?+ E k: i/ t
class Solution {
! T: x$ o+ `+ \
public:
) `$ T0 G: Q7 {0 S
int search(vector<int>& nums, int target) {
- Q3 o# \& ]# w1 B
//区间[left rigth]
9 e* q5 `+ m- A
int left=0;
1 m* X e2 i5 W% \
int right=nums.size()-1;
- I! H( p; @" o1 W/ ]( ?7 F
//结束条件 left>rigth
" C1 f( R; r) w& u# {$ j, m
while(left<=right)
; f1 T* _' w( ?- N& k' f
{
# n! F* z) x7 L1 E$ c+ ~
int middle=left+((right-left)/2);//始终保证 有变量 [left,middle]或[middle rigth]
% H+ Z9 J2 e# b
//[middle+1 right]
: R) K1 d3 k( O1 E. z6 M+ I# m' _
if(nums[middle]<target)
2 l1 o2 E/ P% t7 w1 a, Y' o; N
{
7 \- O2 g/ K/ I; \, J+ s8 x
left=middle+1;
( n0 m7 |% w8 g) v
}
?( P7 \" m* x
//[left middle-1]
0 a3 o5 b4 e$ D: d4 Y8 O" W/ X5 c5 ~, E
else if(nums[middle]>target)
* m2 M9 q- Z: Y6 T4 l2 b
{
* |7 o |) K) ^9 Y3 Z4 ?. E w0 U
right=middle-1;
3 k) Y" m# z6 A+ J
}
' U! g2 z3 I4 |" _
else{
+ d" {- _! G& @! r! X3 L! U
return middle;
$ A% F8 h+ e9 x
}
4 D$ t4 S) C9 e5 T
/ |$ K( K+ Z. J% t( j
}
) Z* ?2 L+ f: X7 w0 o/ C
return -1;
^6 I. u0 I2 g/ c* X# s9 l
9 b; N6 P2 l8 l$ Z9 K
}
. k, B) B4 a- G# \0 v
};
0 v9 Y* k) M" e: q
* A ~% j& \2 v& v
注意:
g5 ~2 W Z9 I3 Q1 F5 ~9 I
. v8 X: g* h6 ]9 j
(1)设立区间为[left, right],终止条件为left>rigth
* I, h0 h( t/ _ [4 A
(2) (left + right)/2==int middle = left + ((right - left) / 2)
5 X% e7 }7 Y) S) T: @" ^( z, ~
(3) 通过改变区间的左右值;复杂度logn
* y& O: F1 q# ]) y& N% c8 C' ]
2 B: X9 p9 o+ L" h: ]
2.leetcode 27移除元素
+ n5 ^5 O0 n, Z8 t
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
. }# V* Y, o; y5 b [, Z
; B* E; f2 t9 P7 Q" u y
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
, g& H4 |2 Y/ Z2 u- r: A
+ B4 g- d' I' t9 i1 r( `
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
7 O8 X2 ^, i: c
* A! A+ ]. C/ R# U- `3 f y
示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。
- W+ [$ o3 U# E; {1 K; o. O7 e
6 p) Z7 x" [6 E6 e/ Q8 u- d
示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
, A0 @0 C2 w5 n0 J: e
9 i0 p3 B$ T+ g& R5 N7 T5 `& A5 P
思路:要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。
0 h9 m+ r/ Y7 C1 x! w5 S5 _! B3 ^
% h% I) S; w0 W$ w
方法:双指针
! X9 d( X; _& w" m% L
0 ~' w G4 D f+ v+ |
class Solution {
8 K1 v3 U( g0 K9 g1 Z
public:
- W9 k1 J2 e, W6 Y; g6 z6 d' _
int removeElement(vector<int>& nums, int val) {
; D$ l1 y. X/ X3 _
int solwIndex=0;
) T& Y- e" C1 V& I4 Z
for(int fastIndex=0;fastIndex!=nums.size();fastIndex++)
. Z# q" u0 Z9 v" _4 E
{
2 x! w* w% B: B8 o: t' B b
if(nums[fastIndex]!=val)
0 H" O9 t+ u W5 E9 Q' ]
{
' J- l+ ?" Y" T) [
nums[solwIndex++]=nums[fastIndex];
' C! C2 |! k7 |
}
$ M( O- Y2 P# ?& ^
}
2 n# y% c2 K5 Z1 P, ?
return solwIndex;
9 v* h6 i- G. d) {
}
* t2 ]2 S: @& y( s' [ P
};
% N. M" y/ a& P2 j4 |. W
solwindex:用来覆盖
! I" B! G' j v) u2 f
( p% g( a3 u% e0 X5 {7 d1 Y
fastindex:来找删除元素++
! D0 H1 S- @5 F. |9 Z/ G& v7 F
. A8 w7 H4 _0 U8 K
3.有序数组的平方
7 ?3 ^2 k" T/ W7 y9 Y7 P7 n/ S
给你一个按 非递减顺序 排序的整数数组 A,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
: o! R8 v+ B) J. R# _. f
& X/ @ A* J5 Q
数组其实是有序的, 只不过负数平方之后可能成为最大数了。
) t0 h$ b* s; }* E
% A! G8 ?1 f; a" H- D! `5 T1 Q
那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
( u R; p/ z2 a( k& g+ |; j1 C* ^
4 c/ Z# K! s# g& @5 y
此时可以考虑双指针法了,
+ |5 L$ Y! Y: ?1 y: r
& c$ f$ {- p" ?
i指向起始位置(负数),j指向终止位置(正数)。
: H6 U8 ]: S! Y' g! h" n
% f- }! S# e% I2 h
定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。
- ^/ n0 q: X: n: N# z8 \% r/ P
+ ~0 ]& [, _( A* f
如果A
* A
< A[j] * A[j] 那么result[k--] = A[j] * A[j]; 。
/ K5 {. T9 \' v& n8 N
, C- C7 @/ d5 ~+ Q6 w
如果A
* A
>= A[j] * A[j] 那么result[k--] = A
* A
;
$ G7 t* e& [, \7 ]5 {4 V- `+ T# S
% i/ h5 z8 f C! a% ~* R* v
class Solution {
) D0 Z O7 i$ h, P# O5 l* V
public:
# l* V7 e, k6 _
vector<int> sortedSquares(vector<int>& A) {
9 r- j' y1 s) O4 P& J
int k=A.size()-1;
; W1 I$ @7 z' y0 V3 W' ?
vector<int> result(A.size(),0);
& ]7 _5 I+ ^; k$ m! q
for(int i=0,j=A.size()-1;i<=j;)
E6 T( G0 i& R( @; S- t% _
{
- l: B4 l% p+ L9 c, e: D* m
//遍历一遍
( |; t+ W0 g0 y" T3 L) p7 f
if(A
*A
<A[j]*A[j])
, b) q* D4 K1 f& p8 g& O/ C o( P
{
8 S" c. D& N x) w3 f
result[k--]=A[j]*A[j];
! f& p5 B8 p) w+ F1 l
j--;
# @+ ?- G, p0 ]
}
( K, q* G2 A- j' x; S/ U
else
& {! N D7 F! _9 {& W: e+ a Q
{
- ]7 n* x2 U! R3 H' ^1 f1 _$ }6 J
result[k--]=A
*A
;
& k! Z. r6 r, z1 p
i++;
- C2 V, q, _/ g n
}
' N; p, z' h( u+ V' r" F
}
! m2 B, p$ j1 _( T0 [% R
return result;
0 W3 L. T' W! C0 I4 A M
9 o% [' a7 R9 v+ r. E
}
: J+ w5 k9 ?; B, W) ?
};
0 B9 Q$ x6 e. W" j/ l9 g; I
4 W6 A# Y8 j& n- ]1 n
4.长度最小的子数组
2 v* G0 W( Z) A
给定一个含有 n 个正整数的数组和一个正整数 target 。
. \& A4 [( ]/ |* _ J* w% P* Q5 m
% ?# v4 ~7 y" F
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
* I' a% t: G: B, Q
O3 o/ @6 t5 T+ m
方法:滑动窗口法
6 f& H$ [% l& H0 O& B1 u# I" e
1 f# }; K( w! h' B) t4 i2 y+ i
就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
, l, \2 h/ F- r# q5 e
( H x# n) ^% j- _/ m, k3 D
三点重要:
1 Z" H& M$ i4 Y' A
: \7 S& L( ]- F3 V" l Z
窗口内是什么?
. @# _! f' \) g$ m q, t1 j
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
p+ H0 J& v7 B: `% P
如何移动窗口的起始位置?
5 ]! t1 X# n- M! R9 ?
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了
! j- m" c1 x8 s0 Z
如何移动窗口的结束位置?
& ?% t/ ]8 K" M' K. P" x
窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
: `# K1 H3 w0 P# ?
6 y; X% Z E* A1 C3 u# Q
代码如下
+ y/ }* z) c' W9 i
3 k/ Q5 {3 w3 N" i! s9 X4 O
class Solution {
1 e8 t+ \# S9 w8 J9 v
public:
& n, y6 o7 @/ B1 a( J- `
int minSubArrayLen(int s, vector<int>& nums) {
" w6 u4 b# e) f: b, C* ^; _
int result = INT32_MAX;
, |& e5 [& m9 V$ {5 k
int sum = 0; // 滑动窗口数值之和
4 ~/ d) C- Y$ t" h; r
int i = 0; // 滑动窗口起始位置
. d$ l# G. R2 w/ q @- i
int subLength = 0; // 滑动窗口的长度
' L1 v0 I8 b ~+ P
for (int j = 0; j < nums.size(); j++) {
2 T) p& }% k" a' @- Q7 _
sum += nums[j];
$ w6 i: W/ B" O) R0 I
// 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
; B# E& Y# d2 L
while (sum >= s) {
* j# U* L) L2 b. D
subLength = (j - i + 1); // 取子序列的长度
4 z& O) a! {& u, q- Q) ^
result = result < subLength ? result : subLength;//一定会赋值
2 k C/ K$ Y `/ I" v+ w
sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
+ R d0 h; ^/ B. R
}
! O6 D/ ~0 G* a1 B! f1 K4 a
}
) T( J% d; Q; c% p" o* f
// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
3 q" p0 x2 Z9 Y9 ^1 ]
return result == INT32_MAX ? 0 : result;
u3 Q+ E4 B4 `0 ?
}
& T! |2 d( q5 Y: O! `
};
5 M. R! Y5 r7 t! i# v
0 Y0 n+ J4 o {( H
一旦大于,就减去左区间的值
. S- Q4 C5 B' S1 I
. j5 h) L6 J. B' X/ F
5.最难题螺旋矩阵||
$ D, q9 k4 B& @+ D
模拟顺时针画矩阵的过程:
, i) a8 p5 V* o5 F7 C! |$ g
( E4 O W( z, C0 r0 W
填充上行从左到右
, J+ `& W: Y+ h: u8 H* d
填充右列从上到下
. \; k' p: m- d. D
填充下行从右到左
b9 D" q: q2 g$ w9 t$ y5 p
填充左列从下到上
: C/ O2 D; E1 c8 L
由外向内一圈一圈这么画下去。
5 s* ]3 A) s4 o3 _3 R
- _. F% U3 j% T5 v6 v
这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。
: v4 l R$ h# @
% K, E) ^ o. v
6 I; f6 m( Z: v& U f
6 a. G- U+ k* H
/ t# A3 x) W* t; A0 Y! F$ P! P
1 `1 ?) `4 w% `: }1 n/ B( Y$ X: c/ {
class Solution {
) z7 H- y! ]" C
public:
3 l# X' o# H8 Q% B& _1 b" m
vector<vector<int>> generateMatrix(int n) {
* ?0 F4 g& t9 H* [
vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
4 G; ~9 `* [' R3 w* g' k( J
int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
( l Q: v, y) D& M
int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
6 ?7 l- g$ [: o, \, V) [
int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
/ y! x. O8 a% O. f
int count = 1; // 用来给矩阵中每一个空格赋值
/ H, |; Q, T' g# R
int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
( J& X! f& _: d5 m0 U
int i,j;
5 w9 Z( u6 D2 J! \( A
while (loop --) {
* b' z: b0 k3 v4 T; N" ~ E
i = startx;
A- P! U* p' n+ O; q2 a' v( u
j = starty;
* R8 u' R# E! d2 ~/ g) C* U& v4 A
* ~7 K+ n9 Z* F; ?) M1 T4 _
// 下面开始的四个for就是模拟转了一圈
2 g2 T1 q( q3 O5 c3 O' S
// 模拟填充上行从左到右(左闭右开)
8 ~, |4 m, D6 i0 A
for (j = starty; j < n - offset; j++) {
1 Q: o9 K# P6 E/ } \6 `1 w
res[startx][j] = count++;
) h- i4 O' T7 I' i
}
; y0 n6 ^5 d c4 H& R' C
// 模拟填充右列从上到下(左闭右开)
0 D" E" d! [. _5 {- h" H6 f1 H
for (i = startx; i < n - offset; i++) {
7 ^& f1 ?* m. e- }! r
res
[j] = count++;
& [/ x0 g8 O, O* s& ~
}
3 w9 k* {" R- o, y# {6 b$ P
// 模拟填充下行从右到左(左闭右开)
! e4 Y7 [4 n; i! E) W3 a: L0 O
for (; j > starty; j--) {
& {$ i4 M* f5 _
res
[j] = count++;
. w4 w- C4 R8 ?* j/ g
}
9 l9 O8 N, R6 q8 \$ q0 X
// 模拟填充左列从下到上(左闭右开)
3 J" b- M% K4 S, i, t
for (; i > startx; i--) {
' L, O7 ~6 w, c
res
[j] = count++;
2 N4 U0 D8 u X' R/ d6 d' x; f
}
" n, s! ?5 X- o o
* T( k" o; X+ j+ M
// 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
/ h: R4 {% M, a0 Z6 D
startx++;
1 V8 G- G! C) d/ r6 F) b0 ?4 {$ e
starty++;
+ l, o+ D R0 {- r
" ]' g; R: o5 B# ]
// offset 控制每一圈里每一条边遍历的长度
3 Q! @' ?) t/ d* @' G! e' I
offset += 1;
8 q5 t8 ]* U( L/ x* r# C3 v( E
}
# Y" `4 W% R( e: }1 D0 y$ |
Z( P$ J, R: i7 @/ a7 W
// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
3 Q) c" t0 e+ D: S$ ]: z( y
if (n % 2) {
6 Y9 `9 l7 m/ J, k# q2 F+ ?
res[mid][mid] = count;
5 ]) c& D# h- Y9 b' F
}
0 g0 J" }5 i7 m% ?5 ^: E4 {
return res;
5 H$ ?8 T4 E" w a7 V9 z
}
; l: v/ c& M+ W3 O: u% R" n
};
{+ Z/ Q" @& ] H; `* k7 L
# E/ m" {3 J# c+ T* C# E
————————————————
3 E. x" B! b x) g, P
版权声明:本文为CSDN博主「编程界的谢菲尔德」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
8 H! U% z0 T2 t$ h- z; R/ d& N! I* Y
原文链接:https://blog.csdn.net/qq_62309585/article/details/126745039
! v* c4 a- J8 D' ^ m
. Y Y+ c8 Q( ]9 _0 f4 Z
4 M( z# n2 q: q! I8 L1 V7 g) `$ B
欢迎光临 数学建模社区-数学中国 (http://www.madio.net/)
Powered by Discuz! X2.5