数据结构【数组、矩阵】相关代码(数据结构笔试、复测、Leecode、牛客)

简单

两数之和

描述

给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。
(注:返回的数组下标从1开始算起,保证target一定可以由数组里面2个数字相加得到)

解题思路:

  • 两个for循环(缺点:超时)
  • 哈希表<取值, 下标>
class Solution {
public:
    /**
     * 
     * @param numbers int整型vector 
     * @param target int整型 
     * @return int整型vector
     */
    vector<int> twoSum(vector<int>& numbers, int target) {
        // write code here
        vector<int> res;
        int n = numbers.size();
        if(n==0)
            return res;
        
        unordered_map<int, int> haxi;//定义哈希表,<取值,下标>
        for(int i=0; i<n; i++){
            if(haxi.count(target-numbers[i])){ //找到执行,没找到不执行
                res.push_back(haxi[target-numbers[i]]+1);
                res.push_back(i+1);
                break;
            }else{
                //将未找到的值插入哈希表中
                haxi[numbers[i]] = i;
            }
        }
        return res;
    }
    
//        for(int i=0; i<numbers.size()-1; i++){
//            for(int j=i+1; j<numbers.size(); j++){
//                if(numbers[i] + numbers[j] == target){
//                    res.push_back(i+1);
//                    res.push_back(j+1);
//                    return res;
//                }     
//            }
//        }
//        return res;
//    }
};

合并两个有序的数组

描述

给出一个有序的整数数组 A 和有序的整数数组 B ,请将数组 B 合并到数组 A 中,变成一个有序的升序数组

注意

1.保证 A 数组有足够的空间存放 B 数组的元素, A 和 B 中初始的元素数目分别为 m 和 n,A的数组空间大小为 m+n
2.不要返回合并的数组,将数组 B 的数据合并到 A 里面就好了,且后台会自动将合并后的数组 A 的内容打印出来,所以也不需要自己打印
3. A 数组在[0,m-1]的范围也是有序的

思路:

  • step 1:使用三个指针,i指向数组A的最大元素,j指向数组B的最大元素,k指向数组A空间的结尾处。
  • step 2:从两个数组最大的元素开始遍历,直到某一个结束,每次取出较大的一个值放入数组A空间的最后,然后指针一次往前。
  • step 3:如果数组B先遍历结束,数组A前半部分已经存在了,不用管;但是如果数组A先遍历结束,则需要把数组B剩余的前半部分依次逆序加入数组A前半部分,类似归并排序最后的步骤。
class Solution {
public:
    void merge(int A[], int m, int B[], int n) {
        int i = m-1, j = n-1, k = m+n-1;
        while(i>=0 && j>=0){
            if(A[i] > B[j])
                A[k--] = A[i--];
            else
                A[k--] = B[j--];
        }
        if(i < 0){
            while(j>=0)
                A[k--] = B[j--];
        }
    }
};

螺旋矩阵

描述

给定一个m x n大小的矩阵(m行,n列),按螺旋的顺序返回矩阵中的所有元素。

在这里插入图片描述
解题:

  • 四个边界—上边界、下边界、左边界、右边界
  • 直到边界重合
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int> > &matrix) {
        vector<int> res;
        int n = matrix.size();
        if(n == 0)
            return res;
        //左边界、右边界、上边界、下边界
        int left = 0;
        int right = matrix[0].size() -1;
        int top = 0;
        int down = n-1;
        
        //直到边界重合
        while(left <= right && top <= down){
            //上边界从左到右
            for(int i=left; i<=right; i++)
                res.push_back(matrix[top][i]);
            top++;
            if(top>down)
                break;
            //右边界从上到下
            for(int i=top; i<= down; i++)
                res.push_back(matrix[i][right]);
            right--;
            if(left>right)
                break;
            //下边界从右到左
            for(int i=right; i>=left; i--)
                res.push_back(matrix[down][i]);
            down--;
            if(top>down)
                break;
            //左边界从下到上
            for(int i=down; i>=top; i--)
                res.push_back(matrix[i][left]);
            left++;
            if(left>right)
                break;
        }
        return res; 
    }
};

斐波那契数列

在这里插入图片描述
递归

class Solution {
public:
    int Fibonacci(int n) {
        if(n == 1 || n== 2)
            return 1;
        return Fibonacci(n-1) + Fibonacci(n-2);
    }
};

中等

最长无重复子数组

描述

给定一个长度为n的数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。
子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组

解题思路

  • step 1:构建一个哈希表,用于统计数组元素出现的次数。
  • step 2:窗口左右界都从数组首部开始,每次窗口优先右移右界,并统计进入窗口的元素的出现频率。
  • step 3:一旦右界元素出现频率大于1,就需要右移左界直到窗口内不再重复,将左边的元素移除窗口的时候同时需要将它在哈希表中的频率减1,保证哈希表中的频率都是窗口内的频率。
  • step 4:每轮循环,维护窗口长度最大值。
class Solution {
public:
    /**
     * 
     * @param arr int整型vector the array
     * @return int整型
     */
    int maxLength(vector<int>& arr) {
        // write code here
        unordered_map<int, int> mp;
        int res = 0;
        int j = 0;
        for(int i=0; i<arr.size(); i++){
            
            //右移进入哈希表统计出现次数
            mp[arr[i]]++;
            //出现次数大于1,有重复
            while(mp[arr[i]] > 1)
                mp[arr[j++]]--;
            res = max(res, i-j+1);
        }
        return res;
    }
};

三数之和

描述

给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。

数据范围:0≤n≤3000,数组中各个元素值满足 ∣val∣≤100
空间复杂度:O(n^2),时间复杂度 O(n^2)

注意:

三元组(a、b、c)中的元素可以按任意顺序排列。
解集中不能包含重复的三元组。
输入:[-10,0,10,20,-10,-40]
返回值:[[-10,-10,20],[-10,0,10]]

思路:

  • 如果找到了某个数a,要找到与之对应的另外两个数,三数之和为0,等价于只要找到另外两个数之和为−a

具体做法:

  • step 1:排除边界特殊情况。
  • step 2:既然三元组内部要求非降序排列,那我们先得把这个无序的数组搞有序了,使用sort函数优先对其排序。
  • step 3:得到有序数组后,遍历该数组,对于每个遍历到的元素假设它是三元组中最小的一个,那么另外两个一定在后面。
  • step 4:需要三个数相加为0,则另外两个数相加应该为上述第一个数的相反数,我们可以利用双指针在剩余的子数组中找有没有这样的数对。双指针指向剩余子数组的首尾,如果二者相加为目标值,那么可以记录,而且二者中间的数字相加可能还会有。
  • step 5:如果二者相加大于目标值,说明右指针太大了,那就将其左移缩小,相反如果二者相加小于目标值,说明左指针太小了,将其右移扩大,直到两指针相遇,剩余子数组找完了。
    注:对于三个数字都要判断是否相邻有重复的情况,要去重。
class Solution {
public:

    static bool cmp(int x, int y){
        return x<y;
    }
    vector<vector<int> > threeSum(vector<int> &num) {
        vector<vector<int>> res;
        int n = num.size();
        if(n < 3)
            return res;
        //对num排序
        sort(num.begin(), num.end(),cmp);
        
        for(int i=0; i<n-2; i++){
            if(i != 0 && num[i] == num[i-1])
                continue;
            int left = i+1;
            int right = n-1;
            int target = -num[i]; //两数相加为-num[i]
            while(left < right){
                if(num[left] + num[right] == target){
                    res.push_back({num[i], num[left], num[right]});
                    //去重复
                    while(left+1 < right && num[left] == num[left+1])
                        left++;
                    while(right-1 > left && num[right] == num[right-1])
                        right--;
                    left++;
                    right--;
                }else if(num[left] + num[right] > target)
                    right--;
                else
                    left++;
            }
        }
        return res;
        
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值