数据结构基础训练 数组与字符串

LeetCode题目

寻找数组的中心索引

给你一个整数数组 nums,请编写一个能够返回数组 “中心下标” 的方法。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果数组不存在中心下标,返回 -1 。如果数组有多个中心下标,应该返回最靠近左边的那一个。
注意:中心下标可能出现在数组的两端。

代码1(C#)

public class Solution {
    public int PivotIndex(int[] nums) {
        int left = 0, right = 0;
        if(nums==null||nums.Length==0)
            return -1; 
         for( int i = 1; i < nums.Length ; i++)
            right += nums[i];       
        if( left == right)
            return 0;
        for(int i = 1; i<nums.Length; i++){         
           left+=nums[i];
            if(i>0)
                right-=nums[i-1];
            if(left==right)
                return i;
        }
        return -1;

    }
}

在这里插入图片描述

代码2(C++)

class Solution {
public:
    int pivotIndex(vector<int>& nums) {
        int left = 0, right = 0;
        if(nums.empty())
            return -1; 
         for( int i = 1; i < nums.size() ; i++)
            right += nums[i];
        
        if( left == right)
            return 0;

        for(int i = 1; i<nums.size() ; i++){
          
           left+=nums[i];
            if(i>0)
                right-=nums[i-1];
            if(left==right)
                return i;
        }
        return -1;

    }
};

在这里插入图片描述

搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

代码1(C#)

public class Solution {
    public int SearchInsert(int[] nums,int target) {
         for(int i=0;i<nums.Length;i++){
            while(target<=nums[i])
                return i;
        }
        return nums.Length;
    }
}

在这里插入图片描述
代码2(C++)

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        for(int i = 0; i < nums.size(); i++){
            while(target <= nums[i])
                return i;
        }
        return nums.size();
    }
};

在这里插入图片描述

旋转矩阵

给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。

不占用额外内存空间能否做到?

代码1(C#)

public class Solution {
    public void Rotate(int[][] matrix) {
        int a,n=matrix.Length;
        for(int i = 0;i < n / 2;i++)
            for(int j=0;j<n;j++)
            {a=matrix[i][j];
             matrix[i][j]=matrix[n-i-1][j];
             matrix[n-i-1][j]=a; 
             }       
        for(int i=0;i<n;i++)
            for(int j=0;j<i;j++) {
             a=matrix[i][j];
             matrix[i][j]=matrix[j][i];
             matrix[j][i]=a; 
            }
    }
}

在这里插入图片描述

代码2(Python)

class Solution(object):
    def rotate(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: None Do not return anything, modify matrix in-place instead.
        """
        n = len(matrix[0])        
        for i in range(n):
            for j in range(i, n):
                matrix[j][i], matrix[i][j] = matrix[i][j], matrix[j][i] 
            matrix[i].reverse()

在这里插入图片描述

知识点总结

数组简介

集合

集合的定义:由一个或多个确定的元素所构成的整体。

集合的特性
1.集合里的元素类型不一定相同。 你可以将商品看作一个集合,也可以将整个商店看作一个集合,这个商店中有人或者其他物品也没有关系。
2.集合里的元素没有顺序。

列表

列表(又称线性列表)的定义:是一种数据项构成的有限序列,即按照一定的线性顺序,排列而成的数据项的集合。
列表的概念是在集合的特征上形成的,它具有顺序,且长度是可变的。

列表最常见的表现形式:数组和链表,栈和队列则是两种特殊类型的列表。

数组

数组是列表的实现方式,它具有列表的特征,同时也具有自己的一些特征。

如何区分列表和数组
1.数组会用一些名为 索引 的数字来标识每项数据在数组中的位置,且在大多数编程语言中,索引是从 0 算起的。我们可以根据数组中的索引,快速访问数组中的元素。
而列表中没有索引,这是数组与列表最大的不同点。
2.数组中的元素在内存中是连续存储的,且每个元素占用相同大小的内存。

数组的操作
读取元素,查找元素,插入元素,删除元素。

二维数组简介

二维数组是一种结构较为特殊的数组,只是将数组中的每个元素变成了一维数组。所以二维数组的本质上仍然是一个一维数组,内部的一维数组仍然从索引 0 开始,我们可以将它看作一个矩阵。
在这里插入图片描述

字符串简介

简介:字符串是由零个或多个字符组成的有限序列。一般记为 s = a1a2…an。它是编程语言中表示文本的数据类型。

为何单独讨论字符串类型:
我们知道,字符串与数组有很多相似之处,比如使用 名称[下标] 来得到一个字符。那么我们为什么要单独讨论字符串呢?原因主要有:
1.字符串的基本操作对象通常是字符串整体或者其子串
2. 字符串操作比其他数据类型更复杂(例如比较、连接操作)

连接操作:
对于不同的编程语言中,字符串可能是可变的,也可能是不可变的。不可变意味着一旦字符串被初始化,你就无法改变它的内容。
在某些语言(如 C ++)中,字符串是可变的。 也就是说,你可以像在数组中那样修改字符串。
在其他一些语言(如 Java、Python)中,字符串是不可变的。不可变字符串无法被修改。哪怕你只是想修改其中的一个字符,也必须创建一个新的字符串。

双指针技巧

情景一

我们通过迭代数组来解决一些问题。通常,我们只需要一个指针进行迭代,即从数组中的第一个元素开始,最后一个元素结束。然而,有时我们会使用两个指针进行迭代。

让我们从一个经典问题开始:
反转数组中的元素。比如数组为 [‘l’, ‘e’, ‘e’, ‘t’, ‘c’, ‘o’, ‘d’, ‘e’],反转之后变为 [‘e’, ‘d’, ‘o’, ‘c’, ‘t’, ‘e’, ‘e’, ‘l’]。

在这里插入图片描述

使用双指针技巧,其思想是分别将两个指针分别指向数组的开头及末尾,然后将其指向的元素进行交换,再将指针向中间移动一步,继续交换,直到这两个指针相遇。

**使用双指针的典型场景之一是你想要从两端向中间迭代数组。**这时你可以使用双指针技巧:
一个指针从头部开始,而另一个指针从尾部开始。这种技巧经常在排序数组中使用。

情景二

我们可以使用两个不同步的指针来解决问题,即快慢指针。与情景一不同的是,两个指针的运动方向是相同的,而非相反。

让我们从一个经典问题开始:
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

如果我们没有空间复杂度上的限制,那就更容易了。我们可以初始化一个新的数组来存储答案。如果元素不等于给定的目标值,则迭代原始数组并将元素添加到新的数组中。

实际上,它相当于使用了两个指针,一个用于原始数组的迭代,另一个总是指向新数组的最后一个位置。

考虑空间限制
如果我们不使用额外的数组,只是在原数组上进行操作呢?
此时,我们就可以采用快慢指针的思想:初始化一个快指针 fast 和一个慢指针 slow,fast 每次移动一步,而 slow 只当 fast 指向的值不等于 val 时才移动一步。

使用双指针技巧的另一种非常常见的情况:同时有一个慢指针和一个快指针。
解决这类问题的关键是:确定两个指针的移动策略。
与前一个场景类似,你有时可能需要在使用双指针技巧之前对数组进行排序,也可能需要运用贪心法则来决定你的运动策略。

学习心得

在学习数组与字符串中,我更好地巩固了以往所学的知识,并不断接触新的算法,通过不断练习训练,和阅读他人的学习文章,对算法的优化有了自己的理解,意识到技术的变化多端和思维转变对程序的巨大影响。明白了时间复杂度和空间复杂度对算法的重要性,有时一个小的变化,也能减少时间和空间,提高效率。多种语言对同一问题的不同切入角度,也扩宽了我的思维,更高层度理解计算机世界的宏大。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值