数据结构:3-1 Array 实战题目

1 题目1:移动零

相关链接:https://leetcode-cn.com/problems/move-zeroes/

  • 给定一个数组 nums,编写一个函数将所有 0移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:

必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。

思路1:

  • 设置j,遍历第一次时,记录当前有多少非0的元素;每碰到非0元素时,将该元素左移。此时j指向最后一个非0元素
  • 第二次遍历,从j开始设置剩下的元素为0

思路2:

  • 快速排序的思想,将0的元素交换到最后

public class MoveZeroes {

    public void moveZeroes(int[] nums){
        int j = 0 ;
        for(int n : nums){
            if ( n != 0) {
                nums[j ++] = n;
            }
        }
        for ( int i = j ; i < nums.length ; i ++){
            nums[i] = 0;
        }
    }
    
    public void moveZeroes2(int[] nums) {
       int j = 0 ;
        for(int i = 0 ; i < nums.length ; i ++ ){
            if ( nums[i] != 0) {
                int temp = nums[i];
                nums[i] = nums[j] ;
                nums[j ++] = temp;
            }
        }
        
    }
}

2 题目2:盛最多水的容器

相关链接:https://leetcode-cn.com/problems/container-with-most-water/

  • 给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点(i,ai) 。
  • 在坐标内画 n 条垂直线,垂直线 i的两个端点分别为(i,ai) 和 (i, 0)。找出其中的两条线,使得它们与x轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且n的值至少为 2。

输入:[1,8,6,2,5,4,8,3,7]
输出:49

思路1:

  • 设置左垂直线水平值x,右垂直线水平值y,面积=(y-x)*min(a[y],a[x])
  • 时间复杂度O(n^2)

思路2:

  • 设置两个指针i,j;初始分别指向左边界、右边界;
  • 遍历时,i向右移,j向左移,每一次移动找到 min(a[i],a[j]) 高度,若是a[i]小,则i++,若是a[j]小,则j–;
  • 时间复杂度O(n)
public class MostWater {

    public int maxArea(int[] height) {
        int maxArea = 0;
        for ( int i = 0 ; i < height.length -1 ; i ++) {
            for ( int j = i + 1 ; j < height.length ; j ++) {
                int area = ( j - i) * Math.min(height[i],height[j]);
                maxArea = Math.max(area,maxArea);
            }
        }
        return maxArea;
    }
    
    public int maxArea2(int[] height) {
        int maxArea = 0;
        for ( int i = 0 ,j = height.length -1 ; i < j; ) {
            int minHeight = height[i] < height[j] ? height[i ++] : height[j --];
            int area = ( j - i + 1) * minHeight;
            maxArea = Math.max(area,maxArea);
        }
        return maxArea;
    } 
}

3 题目3:爬楼梯

相关链接:https://leetcode-cn.com/problems/climbing-stairs

  • 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

  • 注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶
  • 完全无思路
  • 找最近重复子问题

思路1:

  • 通过示例1和2 可以看出:走3级台阶,要末 1级后跨2级 要么 2级后跨1级,
  • 即:必须是从(n-1)级或者(n-2)级台阶走到n级,f(n) = f(n-1) + f(n-2),满足斐波那契数列的通项公式
  • 遍历的方式:时间复杂度O(n),空间复杂度O(1)
  • 递归的方式:时间复杂度O(2^n),空间复杂度O(n)
public class ClimbStairs {

    public int climbStairs(int n){
        if( n == 1) return 1;
        if( n == 2) return 2;
        if( n > 2) {
            return climbStairs(n-1) + climbStairs( n -2);
        }
    }

    public int climbStairs2(int n){
        int [] a = new int[n];
        a[0] = 1;
        a[1] = 2;
        for ( int i = 2 ; i < n ; i ++){
            a[i] = a[i-1] + a[i-2];
        }
        return a[n-1];
    }

    public int climbStairs3(int n){
        int f1 = 0 ,f2 = 0 , fn = 1;
        for ( int i = 1 ; i <= n ; i ++){
            f1 = f2;
            f2 = fn;
            fn = f1 + f2;
        }
    }
}

4 题目4:三数之和

相关链接:https://leetcode-cn.com/problems/3sum/

  • 给你一个包含 n 个整数的数组nums,判断nums中是否存在三个元素 a,b,c ,
    使得a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

  • 注意:答案中不可以包含重复的三元组。

示例 :

给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
],


思路1:暴力求解

思路2:hash表,可参考两数和
a+b = -c

思路3:双指针收敛,另外添加头指针

  1. 将数组进行排序,可以直接判断元素是否相加是否为0
  2. 添加头指针t,其值nums[t] = -(a + b),若target >0,则整个函数直接结束
  3. 添加左指针left,比t指针位置大1,保证不重叠
  4. 添加右指针right,位于数组最右端。
  5. 若nums[t] == nums[left],元素重复,continue
    nums[t] + nums[left] + nums[right] > 0,将right左移,使nums[right]变小
    nums[t] + nums[left] + nums[right] < 0,将left右移,使nums[left]变大
    nums[t] + nums[left] + nums[right] = 0,保存值。left右移,right左移。
public class ThreeSum {

    public List<List<Integer>> threeSum(int[] nums) {
        if (nums == null || nums.length <= 2) {
            return Collections.emptyList();
        }
        Set<List<Integer>> result = new LinkedHashSet<>();

        for (int i = 0; i < nums.length - 2; i++) {
            int target = -nums[i];
            Map<Integer, Integer> hashMap = new HashMap<>(nums.length - i);
            for (int j = i + 1; j < nums.length; j++) {
                int v = target - nums[j];
                Integer exist = hashMap.get(v);
                if (exist != null) {
                    List<Integer> list = Arrays.asList(nums[i], exist, nums[j]);
                    list.sort(Comparator.naturalOrder());
                    result.add(list);
                } else {
                    hashMap.put(nums[j], nums[j]);
                }
            }
        }
        return new ArrayList<>(result);
    }

    public List<List<Integer>> threeSum2(int [] nums) {
        Arrays.sort(nums);
        List<List<Integer>> res = new LinkedList<>();
        for(int t= 0 ; t < nums.length - 2; t ++) {
            if ( t == 0 || ( t > 0 && nums[t] !=nums[t-1])) {
                int left = t + 1 ,right = nums.length - 1 , sum = 0 - nums[t];
                while (left < right ) {
                    if ( nums[left] + nums[right] == sum){
                        res.add(Arrays.asList(nums[t],nums[left],nums[right]));
                        while(left < right && nums[left] == nums[left + 1]) left ++;
                        while(left < right && nums[right] == nums[right -1]) right -- ;
                        left ++ ; right --;
                    }else if ( nums[left] + nums[right] < sum) {
                        left ++ ;
                    }else {
                        right --;
                    }
                }
            }
        }
        return res;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rong742954

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值