【Leetcode训练】数据结构入门——数组全刷

目录

217. 存在重复元素——简单

题目描述:

img

题解:

方法一:排序

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. 最大子数组和——简单

题目描述

img

题解

方法一:动态规划

img

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),其中 nnums 数组的长度。我们只需要遍历一遍数组即可求得答案。
  • 空间复杂度:O(1)。我们只需要常数空间存放若干变量。

方法二:动态规划

img

img

复杂度分析

  • 时间复杂度:O(n),其中 nnums 数组的长度。我们只需要遍历一遍数组即可求得答案。
  • 空间复杂度:O(1)。我们只需要常数空间存放若干变量。

1. 两数之和——简单

题目描述

img

题解

方法一:暴力枚举

img

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];
    }
}

复杂度分析

img

方法二:查找表法(哈希表)

img

img

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;
    }
}

复杂度分析

img


88. 合并两个有序数组——简单

题目描述

img

题解

方法一:直接合并后排序

img

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);
    }
}

复杂度分析

img

方法二:双指针

img

img

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];
        }
    }
}

复杂度分析

img

方法三:

img

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);
		}
    }
}

复杂度分析

img

方法三:// 逆向双指针

img

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 为空的时候直接执行此方法
    }
}

复杂度分析

img


350. 两个数组的交集 II——简单

题目描述

img

题解

方法一:使用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;
	}
}

img

方法二:使用映射实现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;
    }

img

方法三:排序预处理(我)

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;
    }
}

复杂度分析

img


121. 买卖股票的最佳时机——简单

题目描述

img

题解

方法一:Dp min、max

思路还是挺清晰的,还是DP思想:

  1. 记录【今天之前买入的最小值】

  2. 计算【今天之前最小值买入,今天卖出的获利】,也即【今天卖出的最大获利】

  3. 比较【每天的最大获利】,取最大值即可

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;
    }
}

img

方法二:暴力(超时)

	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;
	}

复杂度分析

img

方法三:一次遍历

假设给定的数组为:[7, 1, 5, 3, 6, 4]

如果我们在图表上绘制给定数组中的数字,我们将会得到:img

我们来假设自己来购买股票。随着时间的推移,每天我们都可以选择出售股票与否。那么,假设在第 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;
	}
	

img

复杂度分析

img


566. 重塑矩阵——简单

题目描述

img

示例 1:

img

img

示例 2:

img

img

img

题解

方法一:先转为以为数组,然后转为目标数组

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;
    }
}

复杂度分析

img

方法二:二维数组的一维表示

img

(i,j)→i×n+j

同样地,我们可以将整数 xx 映射回其在矩阵中的下标,即

img

img

img

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;
	}
}

复杂度分析

img

img


118. 杨辉三角——简单

题目描述

img

img

img

题解

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;
    }
}

复杂度分析

img

猜你喜欢

转载自blog.csdn.net/qq_45696377/article/details/122743654
今日推荐