重刷LeetCode-数组

更新记录

时间记录(更新题号)
2020年8月11日1480. 一维数组的动态和
1431. 拥有最多糖果的孩子
1512. 好数对的数目
2020年8月12日1470. 重新排列数组
1486. 数组异或操作
1313. 解压缩编码列表
2020年8月18日26. 删除排序数组中的重复项【简单】
1395. 统计作战单位数【中等】
2020年8月22日35. 搜索插入位置【简单】
121. 买卖股票的最佳时机【简单】
27. 移除元素【简单】
2020年9月6日4. 寻找两个正序数组的中位数【困难】

1480. 一维数组的动态和

(1)题目描述

给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。

请返回 nums 的动态和。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/running-sum-of-1d-array

(2)解法与思路

很简单。

class Solution {
    public int[] runningSum(int[] nums) {
       int[] res = new int[nums.length];
        if(nums.length == 0) {
        	return res;
        }
        res[0] = nums[0];
        for(int i = 1; i < nums.length; i++) {
        	res[i] = nums[i] + res[i-1];
        }
        return res; 
    }
}

1431. 拥有最多糖果的孩子

(1)题目描述

给你一个数组 candies 和一个整数 extraCandies ,其中 candies[i] 代表第 i 个孩子拥有的糖果数目。

对每一个孩子,检查是否存在一种方案,将额外的 extraCandies 个糖果分配给孩子们之后,此孩子有 最多 的糖果。注意,允许有多个孩子同时拥有 最多 的糖果数目。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kids-with-the-greatest-number-of-candies

(2)解法与思路

也很简单。

class Solution {
    public List<Boolean> kidsWithCandies(int[] candies, int extraCandies) {
        List<Boolean> res = new ArrayList<Boolean>();
    	int num = candies.length;
    	if(num == 0) {
    		return res;
    	}
    	int max = candies[0];
    	for(int i = 1; i < num; i++) {
    		if(candies[i] > max) {
    			max = candies[i];
    		}
    	}
    	for(int i = 0; i < num; i++) {
    		if(candies[i] + extraCandies >= max) {
    			res.add(true);
    		}
    		else {
    			res.add(false);
    		}
    	}
    	return res;
    }
}

1512. 好数对的数目

(1)题目描述

给你一个整数数组 nums 。

如果一组数字 (i,j) 满足 nums[i] == nums[j] 且 i < j ,就可以认为这是一组 好数对 。

返回好数对的数目。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-good-pairs

(2)思路与解法

解法一:暴力求解,,枚举所有的数对。

class Solution {
    public int numIdenticalPairs(int[] nums) {
        int res = 0;
        int len = nums.length;
        if(len <= 1) {
        	return 0;
        }
        for(int i = 0; i < len; i++) {
        	for(int j = i+1; j < len; j++) {
        		if(nums[i] == nums[j]) {
        			res++;
        		}
        	}
        }
        return res;
    }
}

解法二:组合的方法。统计数组中每个数字出现的次数,假设一个数字M出现了n次,那么总共有n*(n-1)/2个好数对。用哈希表。

class Solution {
    public int numIdenticalPairs(int[] nums) {
        int res = 0;
        int len = nums.length;
        if(len <= 1) {
        	return 0;
        }
        Map<Integer, Integer> m = new HashMap<Integer, Integer>();
        for(int i = 0; i < len; i++) {
        	m.put(nums[i], m.getOrDefault(nums[i], 0)+1);
        }
        
        for (Map.Entry<Integer, Integer> entry : m.entrySet()) {
        	int v = entry.getValue();
            res += v * (v - 1) / 2;
        }
        return res;
    }
}

(3)补充知识

1.Map.getOrDefault(Object key, V defaultValue)方法
当Map集合中有这个key时,就使用这个key值;
如果没有就使用默认值defaultValue。
2.for(Map.Entry<Integer, Integer> entry : m.entrySet()){}
是一种常见的哈希表的遍历方法,entrySet是 java中 键-值 对的集合。遍历方法可以参考下面的博客:

Java中Map的 entrySet()详解以及用法(四种遍历map的方式)

1470. 重新排列数组

给你一个数组 nums ,数组中有 2n 个元素,按 [x1,x2,…,xn,y1,y2,…,yn] 的格式排列。

请你将数组按 [x1,y1,x2,y2,…,xn,yn] 格式重新排列,返回重排后的数组。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shuffle-the-array

(1)题目描述

(2)解法与思路

解法一:遍历,找规律

class Solution {
    public int[] shuffle(int[] nums, int n) {
        int[] res = new int[2*n];
        int index = 0;
        for(int i = 0 ; i < n; i++) {
            res[index++] = nums[i];
            res[index++] = nums[i+n];
        }
        return res;
    }
}

解法二:先找规律,以[0,1,2,3,4,5,6,7],转换后的是[0,4,1,5,2,8,3,7]
i=0 ->0
i=1 ->2
i=2 ->4
i=3 ->6
i=4 ->1
i=5 ->3
i=6 ->5
i=7 ->7
可以推导出:i < n时,第i位的数将会转到2*i处;i > n时,第i位的数将会转到(i-n)*2+1
又有题目中提到,数组中每个数是大于0的,可以用复数来标记是否已经移动到正确的位置。
PS : 这种解法需要满足在任意位置开始,都可以得到一个环。。。这个咋证一下呢?

class Solution {
    public int[] shuffle(int[] nums, int n) {
        for(int i = 0; i < 2 * n; i++) {
            
            int j = i;
            while (nums[i] >= 0) {
                j = getNewSite(j, n);
                int tmp = nums[i];
                nums[i] = nums[j];
                nums[j] = -tmp;
            }
        }
        for(int i = 0; i < 2*n; i++) {
            if(nums[i] < 0) {
                nums[i] = -nums[i];
            }
        }
        return nums;
    }
    public int getNewSite(int oldSite, int n) {
        if(oldSite < n) {
            return oldSite*2;
        }
        else {
            return (oldSite - n) * 2 + 1;
        }
    }
}

(3)补充知识

老生常谈的i++和++i:
i++ 先赋值在运算,例如 a=i++,先赋值a=i,后运算i=i+1,所以结果是a=1
++i 先运算在赋值,例如 a=++i,先运算i=i+1,后赋值a=i,所以结果是a=2

1486. 数组异或操作

(1)题目描述

给你两个整数,n 和 start 。

数组 nums 定义为:nums[i] = start + 2*i(下标从 0 开始)且 n == nums.length 。

请返回 nums 中所有元素按位异或(XOR)后得到的结果。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/xor-operation-in-an-array

(2)思路与解法

暴力求解:

class Solution {
    public int xorOperation(int n, int start) {
        int res = start;
        for(int i = 1; i < n; i++) {
            res = res ^ (start + i * 2);
        }
        return res;
    }
}

1313. 解压缩编码列表

(1)题目描述

给你一个以行程长度编码压缩的整数列表 nums 。

考虑每对相邻的两个元素 [freq, val] = [nums[2i], nums[2i+1]] (其中 i >= 0 ),每一对都表示解压后子列表中有 freq 个值为 val 的元素,你需要从左到右连接所有子列表以生成解压后的列表。

请你返回解压后的列表。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/decompress-run-length-encoded-list

(2)思路与解法

暴力求解,先算出目标数组的长度,再遍历原来的数组,向新数组中填充数字。

class Solution {
    public int[] decompressRLElist(int[] nums) {
        int size = 0;
        for(int i = 0; i < nums.length; i = i + 2) {
            size += nums[i];
        }
        int[] res = new int[size];
        int temp = 0;
        for(int i = 0; i < nums.length; i = i + 2) {
            for(int j = 0; j < nums[i]; j++) {
                res[temp] = nums[i+1];
                temp++;
            }
        }
        return res;
    }
}

26. 删除排序数组中的重复项

(1)题目描述

给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array

(2)思路与解法

双指针,一个去遍历,另一个去标记修改后的位置。

class Solution {
    public int removeDuplicates(int[] nums) {
        if(nums.length == 0) {
            return 0;
        }
        if(nums.length == 1) {
            return 1;
        }
        int i = 1, j = 0;
        for(; i < nums.length && j < nums.length; i++) {
            if(nums[i] != nums[j]) {
                j++;
                nums[j] = nums[i];
            }
        }
        return j+1;
    }
}

1395. 统计作战单位数

(1)题目描述

n 名士兵站成一排。每个士兵都有一个 独一无二 的评分 rating 。

每 3 个士兵可以组成一个作战单位,分组规则如下:

从队伍中选出下标分别为 i、j、k 的 3 名士兵,他们的评分分别为 rating[i]、rating[j]、rating[k]
作战单位需满足: rating[i] < rating[j] < rating[k] 或者 rating[i] > rating[j] > rating[k] ,其中 0 <= i < j < k < n
请你返回按上述条件可以组建的作战单位数量。每个士兵都可以是多个作战单位的一部分。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-number-of-teams

(2)思路与解法

解法一:暴力求解,用三个指针去标记,遍历整个数组。

class Solution {
    public int numTeams(int[] rating) {
        if(rating.length < 3) {
            return 0;
        }
        int n = rating.length;
        int res = 0;
        for(int i = 0, j = 1, k = 2; i < n; k++) {
            //System.out.println(i + " " + j + " " + k);
            if(k == n) {
                if(j != n - 2) {
                    j++;
                    k = j + 1;
                }
                else {
                    if(i != n - 3) {
                        i++;
                    }
                    else {
                        break;
                    }
                    j = i + 1;
                    k = j + 1;
                }
            }
            if((rating[i] > rating[j] && rating[j] > rating[k]) || (rating[i] < rating[j] && rating[j] < rating[k])) {
                res++;
            }
        }
        return res;
    }
}

解法二:统计每个中间士兵左边和右边满足条件的士兵:左边比他小的人数 × 右边比他大的人数 + 左边比他大的人数 × 右边比他小的人数。

class Solution {
    public int numTeams(int[] rating) {
        int n = rating.length;
        int res = 0;
        for (int i = 1; i < n - 1; ++i) {
            int[] left = count(rating, 0, i, rating[i]);
            int[] right = count(rating, i, n, rating[i]);
            res += left[0] * right[1] + left[1] * right[0];
        }
        return res;
    }

    private int[] count(int[] rating, int from, int to, int key) {
        int[] results = new int[2];
        for (int i = from; i < to; ++i) {
            if (rating[i] < key) {
                ++results[0];
            } else if (rating[i] > key) {
                ++results[1];
            }
        }
        return results;
    }
}

35. 搜索插入位置

(1)题目描述

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-number-of-teams

(2)思路与解法

class Solution {
    public int searchInsert(int[] nums, int target) {
        int i = 0;
        for(; i < nums.length; i++) {
            if(nums[i] == target) {
                return i;
            }
            else if(nums[i] > target) {
               break;
            }
        }
        return i;
    }
}

121. 买卖股票的最佳时机

(1)题目描述

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。

注意:你不能在买入股票前卖出股票。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock

(2)思路与解法

解法一:暴力求解

class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length <= 1) {
            return 0;
        }
        int[] tem = new int[prices.length];
        for(int i = 0; i < prices.length; i++) {
            int res = 0;
            for(int j = i + 1; j < prices.length; j++) {
                if(prices[j] - prices[i] > res) {
                    res = prices[j] - prices[i];
                }
            }
            tem[i] = res;
        }
        Arrays.sort(tem);
        return tem[tem.length-1];
    }
}

解法二:用一个变量去记录最低价,并计算今天卖出可以挣到的钱。

class Solution {
    public int maxProfit(int[] prices) {
        int minprice = Integer.MAX_VALUE;
        int maxprofit = 0;
        for (int i = 0; i < prices.length; i++) {
            if (prices[i] < minprice)
                minprice = prices[i];
            else if (prices[i] - minprice > maxprofit)
                maxprofit = prices[i] - minprice;
        }
        return maxprofit;
    }
}

27. 移除元素

(1)题目描述

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-element

(2)思路与解法

用两个指针遍历,发现目标值时,只有i++,j不动,记录下这个位置。

class Solution {
    public int removeElement(int[] nums, int val) {
        int i = 0, j = 0;
        for(; i < nums.length && j < nums.length; i++) {
            //System.out.println(i + " " + j);
            if(nums[i] != val) {
                nums[j] = nums[i];
                j++;
            }
        }
        return j;
    }
}

4. 寻找两个正序数组的中位数

(1)题目描述

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。

请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays

(2)思路与解法

解法一:用双指针,分别遍历两个数组,遍历时比较当前值得大小,最后得到排序在中间的两个数。…这个题隔了两周了,之前写了一半的代码就没改。开始是没有区分这个中位数是否可以直接获取还是要除以2(数组长度为奇数可以去直接取中间的那个数,为偶数就是要除以2),因此标记了两个相邻大小的数字,最后再去叛变中位数的值…代码写的就有点乱了…

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int len1 = nums1.length;
        int len2 = nums2.length;
        int i = 0, j = 0, target1 = Integer.MIN_VALUE, target2 = Integer.MIN_VALUE;
        while(i + j < (len1 + len2)/2 + 1) {
            if(j == len2 || (i < len1 && nums1[i] < nums2[j])) {
                if(target1 < target2) {
                    target1 = nums1[i];
                }
                else {
                    target2 = nums1[i];
                }
                i++;
            }
            else{
                if(target1 < target2) {
                    target1 = nums2[j];
                }
                else {
                    target2 = nums2[j];
                }
                j++;
            }
        }
        if((len1 + len2)%2 == 0) {
            return (target1 + target2)/2.0;
        }
        double result = target1 > target2 ? target1/1.0 : target2/1.0;
        return result;
    }
}

解法二、三:上面那个解法时间复杂度是m+n,达不到log(m+n),可以考虑二分查找,代码还没写,贴一下LeetCode上大神们的思路和解法好了

详细通俗的思路分析,多解法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值