LeetCode算法题(持续更新)

两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

解法:

class Solution {
    public int[] twoSum(int[] nums, int target) {
        for(int i = 0; i < nums.length; i++){
            for(int j = i+1 ; j < nums.length; j++){
                if(target == (nums[i] + nums[j])){
                    return new int[] {i,j};
                }
            }
        }
        throw new IllegalArgumentException("No two sum solution");
    }
}

字典序的第k小数字

给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字。

注意:1 ≤ k ≤ n ≤ 109。

示例 :

输入:
n: 13 k: 2

输出:
10

解释:
字典序的排列是 [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9],所以第二小的数字是 10。

解法:

在这里插入代码片

腐烂的橘子

在给定的网格中,每个单元格可以有以下三个值之一:

值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
每分钟,任何与腐烂的橘子(在 4 个正方向上)相邻的新鲜橘子都会腐烂。

返回直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1。

示例 1:

输入:[[2,1,1],[1,1,0],[0,1,1]]
输出:4
示例 2

输入:[[2,1,1],[0,1,1],[1,0,1]]
输出:-1
解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个正向上。
示例 3:

输入:[[0,2]]
输出:0
解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。

提示:

1 <= grid.length <= 10
1 <= grid[0].length <= 10
grid[i][j] 仅为 0、1 或 2

解法:

class Solution {
    public int orangesRotting(int[][] grid) {
        //当前分钟数
        int times = 0;
        int[][] note = new int[grid.length][grid[0].length];
        boolean finish = false;
        for (int i = 0; i < note.length; i++) {
            for (int j = 0; j < note[0].length; j++) {
                if (grid[i][j] == 2) {
                    note[i][j] = times;
                } else {
                    note[i][j] = -1;
                }
            }
        }
        while (!finish) {
            //开始腐烂
            times++;
            //先假设此次循环后腐烂结束
            finish = true;
            for (int i = 0; i < grid.length; i++) {
                for (int j = 0; j < grid[0].length; j++) {
                    //如果当前循环到的橘子是腐烂的且是上一分钟腐烂的,就查看这个橘子的上下左右是否有单元格且是新鲜的橘子
                    //如果有新鲜橘子则变为腐烂,且腐烂有可能没有结束,finish = false继续下次循环
                    if ((grid[i][j] == 2) && (note[i][j] == (times - 1))) {
                        //左
                        if ((j > 0) && (grid[i][j - 1] == 1)) {
                            grid[i][j - 1] = 2;
                            note[i][j - 1] = times;
                            finish = false;
                        }
                        //上
                        if ((i > 0) && (grid[i - 1][j] == 1)) {
                            grid[i - 1][j] = 2;
                            note[i - 1][j] = times;
                            finish = false;
                        }
                        //右
                        if ((j < (grid[i].length - 1)) &&
                                (grid[i][j + 1] == 1)) {
                            grid[i][j + 1] = 2;
                            note[i][j + 1] = times;
                            finish = false;
                        }
                        //下
                        if ((i < (grid.length - 1)) &&
                                (grid[i + 1][j] == 1)) {
                            grid[i + 1][j] = 2;
                            note[i + 1][j] = times;
                            finish = false;
                        }
                    }
                }
            }
            //如果腐烂结束说明没有新鲜橘子再变腐烂,输出times - 1
            if (finish) {
                times--;
            }
        }
        //再循环一次如果还有新鲜橘子说明不可能所有橘子都被腐烂,返回-1
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 1) {
                    times = -1;
                }
            }
        }
        return times;
    }
}

三数之和

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

注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]

解法:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        //数组排序
        Arrays.sort(nums);
        List<List<Integer>> list = new ArrayList<>();
        int length = nums.length;
        for(int i = 0; i < length; i++){
            //如果nums[i]大于0,则和右侧左右指针三者之和必大于0,且因为数组已经排序,后面的数也一定大于0,直接break跳出循环返回结果
            if(nums[i] > 0) break;
            //如果nums[i] == nums[i-1]结果会重复
            if(i > 0 && nums[i] == nums[i-1]) continue;
            //左指针
            int left = i + 1;
            //右指针
            int right = length - 1;
            while(left < right){
                int sum = nums[i] + nums[left] + nums[right];
                if(sum == 0){
                    list.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    //去重,如果用if判断只能去重一次,如果元素重复2次以上则还是无法完全去重,所以用while循环
                    //sum=0,当nums[left] == nums[left+1]时结果会重复
                    while(left < right && nums[left] == nums[left+1]) left++;
                    //sum=0,当nums[right] == nums[right-1]时结果会重复
                    while(left < right && nums[right] == nums[right-1]) right--; 
                    left++;
                    right--;
                }else if(sum < 0){
                    //如果三数之和小于0,则左指针需要右移
                    left++;
                }else{
                    //如果三数之和大于0,则右指针需要左移
                    right--;
                }
            }
        }
        return list;
    }
}

连续整数求和

给定一个正整数 N,试求有多少组连续正整数满足所有数字之和为 N?

示例 1:

输入: 5
输出: 2
解释: 5 = 5 = 2 + 3,共有两组连续整数([5],[2,3])求和后为 5。
示例 2:

输入: 9
输出: 3
解释: 9 = 9 = 4 + 5 = 2 + 3 + 4
示例 3:

输入: 15
输出: 4
解释: 15 = 15 = 8 + 7 = 4 + 5 + 6 = 1 + 2 + 3 + 4 + 5
说明: 1 <= N <= 10 ^ 9

解法1(超过时间限制)

class Solution {
    public int consecutiveNumbersSum(int N) {
    	int answer = 0;
    	//循环每个整数进行累加
    	for(int i = 1; i < N; i++){
    		int start = i;
    		int result = N;
    		//当前整数到后面整数逐步被N减去,当结果小于0说明该段连续整数无法累加得到N
    		while(result > 0) result -= start++;
    		//如果结果等于0说明该段连续整数可以累加得到N
    		if(result == 0) answer++;
    	}
    	return answer;
    }
}

解法2

思路:利用等差数列求和公式变形得到两个结果作为判断条件.
设首项为a,项数为k根据条件得N的区间在[a,a+k-1]之间(因为是连续整数),根据等差数列求和公式可得
N = (a + a + k - 1)k/2 —> N = a * k + (k - 1)k/2 —> a * k = N - (k - 1)k/2,由此可得结论:

  1. 因为a * k 必然大于0所以可得 (k - 1)k/2 > N
  2. 因为a和k都是正整数,所以N - (k - 1)k/2一定能被k整除
class Solution {
    public int consecutiveNumbersSum(int N) {
        int sum = N;
        int terms = 0;
        //i就是项数
        for(int i = 1; i*(i-1)/2 < sum; i++){
            if((sum - i*(i-1)/2) % i == 0){
                terms++;
            }
        }
        return terms;
    }
}

二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:
给定二叉树 [3,9,20,null,null,15,7],

3
/ \
9  20
  /  \
 15   7

返回它的最大深度 3 。

解法

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null) return 0;
        int leftDepth = maxDepth(root.left);
        int rightDepth = maxDepth(root.right);
        return Math.max(leftDepth,rightDepth) + 1;
    }
}

将上述代码精简可以简化为:

class Solution {
    public int maxDepth(TreeNode root) {
        return root == null ? 0 : Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
    }
}

两两交换链表中的节点

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例:

给定 1->2->3->4, 你应该返回 2->1->4->3.

解法

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        //如果当前节点或下一节点为空说明无法再进行交换,则递归终止
        if(head == null || head.next == null) return head;
        //本级递归要做的是当前节点与next节点交换,并且当前节点指向后面已处理完的链表部分
        ListNode next = head.next;
        head.next = swapPairs(next.next);
        next.next = head;
        //交换完毕,应该返回处理完的链表部分,即head.next
        return next;
    }
}

平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

示例 1:

给定二叉树 [3,9,20,null,null,15,7]

   3
  / \
  9  20
 /  \
15  7

返回 true 。

示例 2:

给定二叉树 [1,2,2,3,3,null,null,4,4]

      1
     / \
    2   2
   / \
  3  3
 / \
4  4

返回 false 。

解法

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        //-1说明不是平衡二叉树,反之则是
        return (depth(root)  != -1);
    }
    
    private int depth(TreeNode root){
        //如果节点为空则说明是空二叉树,必为平衡二叉树
        if(root == null) return 0;
        int left = depth(root.left);
        int right = depth(root.right);
        //判断如果当前节点左右子树已经有不平衡二叉树则立即返回-1避免多运算
        if(left == -1) return -1;
        if(right == -1) return -1;
        //返回当前节点二叉树深度
        return Math.abs(left - right) <= 1 ? Math.max(left,right) + 1 : -1;
    }
}

反转链表

反转一个单链表。
示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

解法1(迭代)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode curr = head;
        ListNode prev = null;
        while(curr != null){
            //保存当前节点指针指向的下一个节点
            ListNode temp = curr.next;
            //当前节点指针指向前一个节点进行反转(如果是循环刚开始那么第一个节点重新指向的就是NULL)
            curr.next = prev;
            //以上反转操作完成当前节点赋值给prev
            prev = curr;
            //临时存放的下一个节点赋值给curr,包括prev的赋值这两次赋值都将用于下一次循环
            curr = temp;
        }
        return prev;
    }
}

解法2(递归)

class Solution {
    public ListNode reverseList(ListNode head) {
        //当前节点指针指向NULL时递归结束
        if(head.next == null) return head;
        //当前节点后面递归反转完毕的链表部分
    	ListNode temp = reverseList(head.next);
        //对当前节点进行反转操作
        head.next.next = head;
        head.next = null;
        //返回反转完成的链表部分
    	return head;
    }
}

翻转一棵二叉树

示例:
输入:

     4
   /   \
  2     7
 / \   / \
1   3 6   9

输出:

     4
   /   \
  7     2
 / \   / \
9   6 3   1

解法

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode invertTree(TreeNode root) {
        //当前根树为空时结束递归
        if(root == null) return root;
        TreeNode left = invertTree(root.left);
        TreeNode right = invertTree(root.right);
        //反转
        root.left = right;
        root.right = left;
        return root;
    }
}

合并两个有序链表

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

解法

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1 == null) return l2;
        if(l2 == null) return l1;
        if(l1.val < l2.val){
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        }else{
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值