数学建模社区-数学中国

标题: 数据结构之数组练习 [打印本页]

作者: 杨利霞    时间: 2022-9-8 09:59
标题: 数据结构之数组练习
数据结构之数组练习
1 F8 q# M6 j' P* y7 q1.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 e6 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 Zpublic:- 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 |. Wsolwindex:用来覆盖! 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 n4.长度最小的子数组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 Oclass 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# v0 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. v6 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! ]" Cpublic:
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