目录
-
- [217. 存在重复元素](https://leetcode-cn.com/problems/contains-duplicate/)——简单
- [53. 最大子数组和](https://leetcode-cn.com/problems/maximum-subarray/)——简单
- [1. 两数之和](https://leetcode-cn.com/problems/two-sum/)——简单
- [88. 合并两个有序数组](https://leetcode-cn.com/problems/merge-sorted-array/)——简单
- [350. 两个数组的交集 II](https://leetcode-cn.com/problems/intersection-of-two-arrays-ii/)——简单
- [121. 买卖股票的最佳时机](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/)——简单
- [566. 重塑矩阵](https://leetcode-cn.com/problems/reshape-the-matrix/)——简单
- [118. 杨辉三角](https://leetcode-cn.com/problems/pascals-triangle/)——简单
217. 存在重复元素——简单
题目描述:
题解:
方法一:排序
class Solution {
public boolean containsDuplicate(int[] nums) {
Arrays.sort(nums);
for(int i=0;i<nums.length-1;i++){
if(nums[i]==nums[i+1]){
return true;
}
}
return false;
}
}
复杂度分析
- 时间复杂度:O(NlogN),其中 N 为数组的长度。需要对数组进行排序。
- 空间复杂度:O(logN),其中 N 为数组的长度。注意我们在这里应当考虑递归调用栈的深度。
方法二:哈希表
java Set自带去重,如果去重后的长度小于原长度,则返回true
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> arr = new HashSet<Integer>();
for(int i : nums){
arr.add(i);
}
return arr.size()<nums.length?true:false;
}
}
复杂度分析
- 时间复杂度:O(N),其中 N 为数组的长度。
- 空间复杂度:O(N),其中 N 为数组的长度。
53. 最大子数组和——简单
题目描述
题解
方法一:动态规划
class Solution {
public int maxSubArray(int[] nums) {
int a = 0;
int max = nums[0];
for (int i : nums) {
a = Math.max(a+i, i);
max = Math.max(a, max);
}
return max;
}
}
复杂度分析
- 时间复杂度:O(n),其中 n 为 nums 数组的长度。我们只需要遍历一遍数组即可求得答案。
- 空间复杂度:O(1)。我们只需要常数空间存放若干变量。
方法二:动态规划
复杂度分析
- 时间复杂度:O(n),其中 n 为 nums 数组的长度。我们只需要遍历一遍数组即可求得答案。
- 空间复杂度:O(1)。我们只需要常数空间存放若干变量。
1. 两数之和——简单
题目描述
题解
方法一:暴力枚举
class Solution {
public int[] twoSum(int[] nums, int target) {
int n = nums.length;
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (nums[i] + nums[j] == target) {
return new int[]{
i, j};
}
}
}
return new int[0];
}
}
复杂度分析
方法二:查找表法(哈希表)
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> hash = new HashMap<>();
int arr[] = new int [2];
for (int i = 0; i < nums.length; i++) {
if (hash.containsKey(target-nums[i])) {
// return new int[] {hash.get(target-nums[i]),i};
arr[0] = hash.get(target-nums[i]);
arr[1] = i;
}
hash.put(nums[i], i);
}
return arr;
}
}
复杂度分析
88. 合并两个有序数组——简单
题目描述
题解
方法一:直接合并后排序
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
for (int i = 0; i < n; i++) {
nums1[m] = nums2[i];
m++;
}
Arrays.sort(nums1);
}
}
复杂度分析
方法二:双指针
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int p1 = 0, p2 = 0;
int[] sorted = new int[m + n];
int cur;
while (p1 < m || p2 < n) {
if (p1 == m) {
cur = nums2[p2++];
} else if (p2 == n) {
cur = nums1[p1++];
} else if (nums1[p1] < nums2[p2]) {
cur = nums1[p1++];
} else {
cur = nums2[p2++];
}
sorted[p1 + p2 - 1] = cur;
}
for (int i = 0; i != m + n; ++i) {
nums1[i] = sorted[i];
}
}
}
复杂度分析
方法三:
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int nums1copy[] = new int[m];
System.arraycopy(nums1, 0, nums1copy, 0, m);
int p = 0; // nums1指针
int p1 = 0; // nums1copy 指针
int p2 = 0; // nums2 指针
while ((p1<m) && (p2<n)) {
if (nums1copy[p1]<nums2[p2]) {
nums1[p] = nums1copy[p1];
p++;
p1++;
}else {
nums1[p] = nums2[p2];
p++;
p2++;
}
}
if (p1<m) {
System.arraycopy(nums1copy, p1, nums1, p1+p2,m+n-p1-p2);
}
if (p2<n) {
System.arraycopy(nums2, p2, nums1, p1+p2, m+n-p1-p2);
}
}
}
复杂度分析
方法三:// 逆向双指针
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int p1 = m-1;
int p2 = n-1;
int p = m+n-1;
while (p1>=0&&p2>=0) {
if (nums1[p1]<nums2[p2]) {
nums1[p] = nums2[p2];
p--;
p2--;
}else {
nums1[p] = nums1[p1];
p--;
p1--;
}
}
System.arraycopy(nums2, 0, nums1, 0, p2+1); // 当nums1 为空的时候直接执行此方法
}
}
复杂度分析
350. 两个数组的交集 II——简单
题目描述
题解
方法一:使用List集合
class Solution {
/**
* 使用集合实现
*/
public int[] intersect(int[] nums1, int[] nums2) {
List<Integer> list1 = new ArrayList<>();
for (int i : nums1) {
list1.add(i);
}
List<Integer> list2 = new ArrayList<>();
for (int i : nums2) {
if (list1.contains(i)) {
list2.add(i);
// 从list1 除去已匹配的数值
list1.remove(Integer.valueOf(i));
}
}
int arr[] = new int[list2.size()];
int j = 0;
for (int i : list2) {
arr[j]=i;
j++;
}
return arr;
}
}
方法二:使用映射实现Map
/**
* 使用映射实现
*/
public int[] intersect_3(int[] nums1, int[] nums2) {
Map<Integer, Integer> map = new HashMap<>(nums1.length);
// 将 nums1 出现的数值及频次放入映射中
for (int num : nums1) {
Integer count = map.get(num);
if (count == null) {
map.put(num, 1);
} else {
map.put(num, ++count);
}
}
List<Integer> list = new ArrayList<>();
for (int num : nums2) {
// 获取映射中该数值出现的频次
Integer count = map.get(num);
if (count != null && count != 0) {
list.add(num);
// 注意每次匹配后,该数值的频次需要减 1(nums1 和 nums2 匹配的数值的频次要相同)
map.put(num, --count);
}
}
int[] res = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
res[i] = list.get(i);
}
return res;
}
方法三:排序预处理(我)
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
List<Integer> list = new ArrayList<>();
Arrays.sort(nums1);
Arrays.sort(nums2);
for (int i = 0,j=0;i<nums1.length && j<nums2.length;) {
if (nums1[i]>nums2[j]) {
j++;
}else if (nums1[i]<nums2[j]) {
i++;
}else {
list.add(nums1[i]);
i++;
j++;
}
}
int arr[] = new int[list.size()];
int num = 0;
for (int i : list) {
arr[num] = i;
num ++;
}
return arr;
}
}
复杂度分析
121. 买卖股票的最佳时机——简单
题目描述
题解
方法一:Dp min、max
思路还是挺清晰的,还是DP思想:
-
记录【今天之前买入的最小值】
-
计算【今天之前最小值买入,今天卖出的获利】,也即【今天卖出的最大获利】
-
比较【每天的最大获利】,取最大值即可
class Solution {
public int maxProfit(int[] prices) {
if(prices.length <= 1) {
return 0;
}
int min=prices[0];
int max = 0;
for (int i = 0; i < prices.length; i++) {
max = Math.max(max,prices[i]-min);
min = Math.min(min, prices[i]);
}
return max;
}
}
方法二:暴力(超时)
public int maxProfit(int[] prices) {
int max =0;
for (int i = 0; i < prices.length-1; i++) {
for (int j = i+1; j < prices.length; j++) {
if (prices[j]-prices[i]>max) {
max = prices[j] - prices[i];
}
}
}
return max;
}
复杂度分析
方法三:一次遍历
假设给定的数组为:[7, 1, 5, 3, 6, 4]
如果我们在图表上绘制给定数组中的数字,我们将会得到:
我们来假设自己来购买股票。随着时间的推移,每天我们都可以选择出售股票与否。那么,假设在第 i 天,如果我们要在今天卖股票,那么我们能赚多少钱呢?
显然,如果我们真的在买卖股票,我们肯定会想:如果我是在历史最低点买的股票就好了!太好了,在题目中,我们只要用一个变量记录一个历史最低价格 minprice,我们就可以假设自己的股票是在那天买的。那么我们在第 i 天卖出股票能得到的利润就是 prices[i] - minprice。
因此,我们只需要遍历价格数组一遍,记录历史最低点,然后在每一天考虑这么一个问题:如果我是在历史最低点买进的,那么我今天卖出能赚多少钱?当考虑完所有天数之时,我们就得到了最好的答案。
public int maxProfit(int[] prices) {
int min = Integer.MAX_VALUE;
int max = 0;
for (int i = 0; i < prices.length; i++) {
if (prices[i]<min) {
min = prices[i];
}else if (prices[i]- min>max) {
max = prices[i] - min;
}
}
return max;
}
复杂度分析
566. 重塑矩阵——简单
题目描述
示例 1:
示例 2:
题解
方法一:先转为以为数组,然后转为目标数组
class Solution {
public int[][] matrixReshape(int[][] mat, int r, int c) {
int m = mat.length;
int n = mat[0].length;
if (m*n!=r*c) {
return mat;
}
int arr [] = new int [m*n];
int index =0;
// 转换为一维数组
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
arr[index] = mat[i][j];
index++;
}
}
// 再将一维数组转换为目标数组
int temp[][]=new int[r][c];
for (int i = 0; i < r;i++) {
for (int j = 0; j < c; j++) {
temp[i][j] = arr[i*c+j];
}
}
return temp;
}
}
复杂度分析
方法二:二维数组的一维表示
(i,j)→i×n+j
同样地,我们可以将整数 xx 映射回其在矩阵中的下标,即
class Solution {
public int[][] matrixReshape(int[][] mat, int r, int c) {
int m = mat.length;
int n = mat[0].length;
if (m*n!=r*c) {
return mat;
}
int arr[][] = new int [r][c];
for (int i = 0; i < m*n; i++) {
arr[i/c][i%c] = mat[i/n][i%n];
}
return arr;
}
}
复杂度分析
118. 杨辉三角——简单
题目描述
题解
class Solution {
public List<List<Integer>> generate(int numRows) {
int arr[][] = new int[numRows][numRows];
for (int i = 0; i < arr.length; i++) {
arr[i][0] = 1;
arr[i][i] = 1;
}
for (int i = 2; i < numRows; i++) {
for (int j = 1; j <=i; j++) {
arr[i][j] = arr[i-1][j] + arr[i-1][j-1];
}
}
List<List<Integer>> lists = new ArrayList<>();
for (int i = 0; i < numRows; i++) {
List<Integer> list = new ArrayList<>();
for (int j = 0; j <=i; j++) {
list.add(arr[i][j]);
}
lists.add(list);
}
return lists;
}
}