1. 合并区间
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
思路:首先先对intervals数组进行排序,按照数组内的第一个元素进行排序,这里要记住Arrays.sort()里面可以传入一个Comparator内部类,然后重写里面的compare方法,按照给定的规则进行排序。对于排好序的intervals数组进行合并区间就比较简单了,进行一些规则的判定即可
class Solution {
public int[][] merge(int[][] intervals) {
//这里要注意如果为空时 返回时null 还是一个空的数组
if(intervals == null || intervals.length == 0) return new int[][]{};
//排序规则
Arrays.sort(intervals, new Comparator<int[]>() {
public int compare(int[] o1, int[] o2){
return o1[0] - o2[0];
}
});
List<int[]> res = new ArrayList<>();
res.add(new int[]{intervals[0][0], intervals[0][1]});
for(int i = 1;i < intervals.length;i++){
int[] temp = intervals[i];
int[] list = res.get(res.size() - 1);
//合并区间
if(temp[0] <= list[1] && temp[1] > list[1]){
res.remove(res.size() - 1);
res.add(new int[]{list[0], temp[1]});
continue;
}
if(temp[0] > list[1]){
res.add(new int[]{temp[0], temp[1]});
continue;
}
}
return res.toArray(new int[res.size()][2]);
}
}
2. 矩阵的最小路径和
给定一个 n * m 的矩阵 a,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,输出所有的路径中最小的路径和。
输入
[[1,3,5,9],[8,1,3,4],[5,0,6,1],[8,8,4,0]]
返回值
12
思路:首先要明确,只要走的每一步的结果是最小的,那么最后的结果就是最小的,所以这里并没有涉及到递归+回溯,所以可以直接使用动态规划,使用一个二维dp数组存下结果。使用动态规划,需要注意的是边界的判定:
- 如果i=0 && j=0 dp[i] [j] = matrix[0] [0](matrix为原数组)
- 如果i=0 && j >= 1,说明当前走的是第一行,那么dp[i] [j] = dp[i] [j - 1] + matrix[i] [j]
- 如果i>=0 && j =0,说明当前走的是第一列,那么dp[i] [j] = dp[i - 1] [j] + matrix[i] [j]
- 其他情况:dp[i] [j] = Math.min(dp[i - 1] [j], dp[i] [j - 1]) + matrix[i] [j]
有了上面方程,就好写出动态规划代码
public class Solution {
/**
*
* @param matrix int整型二维数组 the matrix
* @return int整型
*/
public int minPathSum (int[][] matrix) {
// write code here
int[][] dp = new int[matrix.length][matrix[0].length];
int res = 0;
for(int i = 0; i < matrix.length; i++){
for(int j = 0; j < matrix[0].length; j++){
if(i == 0 && j == 0) dp[i][j] = matrix[0][0];
else if(i == 0 && j >= 1) dp[i][j] = dp[i][j - 1] + matrix[i][j];
else if(i >= 0 && j == 0) dp[i][j] = dp[i - 1][j] + matrix[i][j];
else dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + matrix[i][j];
}
}
return dp[matrix.length - 1][matrix[0].length - 1];
}
}
3. 合并两个有序的数组
思路和归并排序最后的并阶段是一样的,对于两个有序的数组,每次选取两个数组最左边数组较小的那么数字,放在结果数组上
public class Solution {
public void merge(int A[], int m, int B[], int n) {
int[] res = new int[m + n];
int left = 0;
int right = 0;
int i = 0;
while(left < m || right < n){
//有两种情况:①当第二个数组已经为空了,那么将所有的第一个数组加入到结果数组中
// ② 两个数组都还有值,并且第一个数组最左边的数比第二个数组较小
if(right >= n || (left < m && A[left] < B[right])){
res[i++] = A[left++];
}else{
res[i++] = B[right++];
}
}
for(int j = 0;j < i;j++){
A[j] = res[j];
}
}
}
4. 链表中倒数第k个节点
输入一个链表,输出该链表中倒数第k个结点。
如果该链表长度小于k,请返回空
输入
{1,2,3,4,5},1
返回值
{5}
基本思路是先遍历一次链表,得到数组的长度,接下来就好办了。优化的代码是使用两个快慢指针,快指针先走k个节点,接着快慢指针一起走,当快指针到链表尾的时候,慢指针所在的节点就是倒数第k个节点
public ListNode FindKthToTail (ListNode pHead, int k) {
// write code here
ListNode temp = pHead;
int count = 0;
while(temp != null){
count++;
temp = temp.next;
}
if(count < k) return null;
int i = count - k;
while(i-- > 0){
pHead = pHead.next;
}
return pHead;
}
5. 二叉树的z型遍历
写过很多次了,做bfs使用队列
public class Solution {
/**
*
* @param root TreeNode类
* @return int整型ArrayList<ArrayList<>>
*/
public ArrayList<ArrayList<Integer>> zigzagLevelOrder (TreeNode root) {
// write code here
Deque<TreeNode> q = new LinkedList<>();
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
//需要注意这里的放回值 不能返回null
if(root == null) return res;
q.offerFirst(root);
int flag = 1;
while(!q.isEmpty()){
ArrayList<Integer> temp = new ArrayList<>();
for(int i = q.size();i > 0;i--){
TreeNode node = q.pollLast();
temp.add(node.val);
if(node.left != null) q.offerFirst(node.left);
if(node.right != null) q.offerFirst(node.right);
}
if(flag % 2 == 0) Collections.reverse(temp);
res.add(temp);
flag++;
}
return res;
}
}