算法-leetcode刷题

[toc]

LeetCode.1 两数之和

  • 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。
  • 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] result = new int[2];
        // //双重循环  时间复杂度O(n²)
        // for(int i=0; i<nums.length; i++){
        //     for(int j=i+1; j<nums.length; j++){
        //         if(nums[i]+nums[j] == target){
        //             result[0] = i;
        //             result[1] = j;
        //             return result;
        //         }
        //     }
        // }

        //哈希表  O(n)
        HashMap<Integer,Integer> hashMap = new HashMap<Integer,Integer>();
        for(int i=0; i<nums.length; i++){
            if(hashMap.containsKey(nums[i])){
                result[0] = hashMap.get(nums[i]);
                result[1] = i;
            }
            //将数据存入  Key为补数——value为下标
            hashMap.put(target-nums[i], i);
        }
        return result;
    }
}
  • 或者另一种思路:先把数组排序,start、end表示数组下标为0、数组最后一个值的下标。如果nums[start] + nums[end] > target,说明end需要减一;如果nums[start]+ nums[end]<target,说明start需要加1;如果相等则是我们想要的。找到start、end后,再遍历一遍数组,找到对应的结果即可

LeetCode.2 两数相加(大数、链表相加)

  • 给出两个非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照逆序的方式存储的,并且它们的每个节点只能存储一位数字。
  • 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
    您可以假设除了数字 0 之外,这两个数都不会以 0开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        int carry = 0;
        ListNode cursor = new ListNode(-1);
        ListNode result = cursor;
        while(l1 != null || l2 != null || carry>0){
            if(l1 != null){
                carry += l1.val;
                l1 = l1.next;
            }
            if(l2 != null){
                carry += l2.val;
                l2 = l2.next;
            }
            ListNode temp = new ListNode(carry%10);
            cursor.next = temp;
            cursor = temp;
            carry/=10;
        }
        return result.next;
    }
}

LeetCode.67 二进制求和

  • 给定两个二进制字符串,返回他们的和(用二进制表示)。
    输入为非空字符串且只包含数字 1 和 0。
  • 输入: a = "1010", b = "1011"
  • 输出: "10101"
class Solution {
    public String addBinary(String a, String b) {
        // 太容易溢出,错误做法,位数需要满足数据类型。。。
        // int int_a = Integer.parseInt(a,2);
        // int int_b = Integer.parseInt(b,2);
        // int result = int_a + int_b;
        // return Integer.toBinaryString(result);
        //完美做法:类似链表加法
        StringBuffer sb = new StringBuffer();
        int carry = 0, i = a.length()-1, j = b.length()-1;
        while(i >= 0 || j >= 0 || carry != 0){
            if(i >= 0) carry += a.charAt(i--)-'0';
            if(j >= 0) carry += b.charAt(j--)-'0';
            sb.append(carry%2);
            carry /= 2;
        }
        return sb.reverse().toString();
    }
}

LeetCode.112 递归 路径之和Ⅰ(非递归用栈实现)

  • 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
  • 说明:叶子节点是指没有子节点的节点。
  • 示例:给定如下二叉树,以及目标和 sum = 22,
  •   图示:
            5
           / \
          4   8
         /   / \
        11  13  4
       /  \      \
      7    2      1
    
  • 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
class Solution {
    public boolean hasPathSum(TreeNode root, int sum) {
        if(root == null){
            return false;
        }
        if(root.left == null && root.right == null){
            return sum - root.val == 0;
        }
        return hasPathSum(root.left, sum - root.val)||hasPathSum(root.right, sum - root.val);
    }
}

LeetCode.113 递归 路径之和Ⅱ

  • 在路径之和Ⅰ的基础上返回路径
  • 示例:给定如下二叉树,以及目标和sum = 22,
  •   图示:
            5
           / \
          4   8
         /   / \
        11  13  4
       /  \    / \
      7    2  5   1
    

返回:[[5,4,11,2], [5,8,4,5]]

class Solution {
    List<List<Integer>> result = new ArrayList<>();
    List<Integer> inner = new ArrayList<>();
    public void union(TreeNode root, int sum){
        if(root == null){
            return;
        }
        sum -= root.val;
        inner.add(root.val);
        if(root.left == null && root.right == null){
            if(sum == 0){
                //因为List为引用类型,添加进result后修改还是会改变。所以返回的是拷贝(new 一个拷贝)
                result.add(new ArrayList(inner));
            }
            inner.remove(inner.size()-1);
            return;
        }
        if(root.left!=null) union(root.left, sum);
        if(root.right!=null) union(root.right, sum);
        inner.remove(inner.size()-1);
    }
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        union(root, sum);
        return result;
    }
}

LeetCode.120 动态规划or递归 三角形最小路径和

  • leetCode题解 https://leetcode-cn.com/problems/triangle/solution/man-hua-jue-dui-neng-kan-de-dong-de-dong-tai-gui-h/

  • 给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

  •   例如,给定三角形:         存储格式:
            2                     [
           / \                        [2],
          3   4                      [3,4],
         / \ / \                    [6,5,7],
        6   5   7                  [4,1,8,3]
       / \ / \ / \                ]
      4   1   8   3
    
  • 自顶向下的最小路径和为11(即,2+3+5+1= 11)。
    说明:
    如果你可以只使用 O(n)的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。

class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        if(triangle == null || triangle.size() == 0){
            return 0;
        }
        //二维数组dp[][]
        // int[][] dp = new int[triangle.size()+1][triangle.size()+1];
        // for(int i = triangle.size()-1; i>=0; i--){
        //     List<Integer> curTri = triangle.get(i);
        //     for(int j = 0; j<curTri.size(); j++){
                   //dp[i][j]表示从顶点到第i+1层第j+1个节点的最小路径
        //         dp[i][j] = Math.min(dp[i+1][j], dp[i+1][j+1]) + curTri.get(j);
        //     }
        // }

        // // 只需要记录每一层的最小值即可 
        // int[] dp = new int[triangle.size()+1];
        // for(int i = triangle.size()-1; i>=0; i++){
        //     List<Integer> curTri = triangle.get(i);
        //     for(int j  = 0; j<curTri.size(); j++){
        //         //这里的dp[j] 使用的时候默认是上一层的,赋值之后变成当前层
        //         dp[j] = Math.min(dp[j], dp[j+1]) + curTri.get(j);
        //     }
        // }
        // return dp[0][0];
        
        //标准On
        int n = triangle.size();
        int[] dp = new int[n];
        for(int i = 0; i < n; i++) 
          dp[i] = triangle.get(n - 1).get(i);
        for(int i = n - 2; i >= 0; i--) {
          for(int j = 0; j <= i; j ++) {
            dp[j] = Math.min(dp[j], dp[j+1]) + triangle.get(i).get(j);
          }
        }    
        return dp[0];

        //递归法
        //return minimumTotalHelper(triangle, 0, 0, new int[triangle.size()][triangle.size()]); 
    }

    int minimumTotalHelper(List<List<Integer>> triangle, int row, int col, int[][] memo){
        if(memo[row][col] != 0) return memo[row][col];
        if(row == triangle.size()-1){
            return memo[row][col] = triangle.get(row).get(col);
        }
        int left = minimumTotalHelper(triangle, row+1, col, memo);
        int right = minimumTotalHelper(triangle, row+1, col+1, memo);
        return memo[row][col] = Math.min(left,right) + triangle.get(row).get(col);
    }
}

LeetCode.121 动态规划 买卖股票的最好时机1

  • 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
  • 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
  • 注意你不能在买入股票前卖出股票。
    • 输入: [7,1,5,3,6,4]
    • 输出: 5
    • 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。注意利润不能是 7-1 = 6,因为卖出价格需要大于买入价格。
    • 输入: [7,6,4,3,1]
    • 输出: 0
    • 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.size()<2) return 0;
        int min = prices[0];
        int profit = 0;
        for(int i=1; i<prices.size(); i++){
            profit = profit>prices[i]-min?profit:prices[i]-min;            
            min = min>prices[i]?prices[i]:min;
        }
        return profit;
    }
};

LeetCode.206 链表 反转链表

反转一个单链表。
示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
//迭代法:
public ListNode reverseList(ListNode head) {
    ListNode prev = null;
    ListNode curr = head;
    while (curr != null) {
        ListNode nextTemp = curr.next;
        curr.next = prev;
        prev = curr;
        curr = nextTemp;
    }
    return prev;
}
//递归:
public ListNode reverseList(ListNode head) {
    if (head == null || head.next == null) return head;
    ListNode p = reverseList(head.next);
    head.next.next = head;
    head.next = null;
    return p;
}

LeetCode.225 队列实现栈

  • 一个队列就可实现栈,而一个队列需要两个栈来实现!
class MyStack {

    Queue<Integer> queue;

    /** Initialize your data structure here. */
    public MyStack() {
        queue = new LinkedList<Integer>();
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        int size = queue.size();
        queue.add(x);
        for( ; size>0; size--){
            queue.add(queue.remove());
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        return queue.remove();
    }
    
    /** Get the top element. */
    public int top() {
        return queue.peek();
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        if(queue.isEmpty()){
            return true;
        }else{
            return false;
        }
    }
}

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack obj = new MyStack();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.top();
 * boolean param_4 = obj.empty();
 */

LeetCode 面试题57-II 和为target的连续正数序列

  • 输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
  • 序列内的数字由小到大排列,不同序列按照首个数字从小到大排列
示例 1:
输入:target = 9
输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]
class Solution {
    public int[][] findContinuousSequence(int target) {
        List<int[]> result = new ArrayList<>();
        //target肯定是奇数(由两个连续的数相加(奇数加偶数等于奇数))
        //最大的连续子序列肯定是target的一半的上界加下界(target = mid+mid+1)
        int mid = target/2;
        //1.滑动窗口暴力法
        /*
        for(int i=1; i<=mid; i++){
            int sum = 0;
            int j=i;
            while(sum < target){
                sum += j++;
            }
            if(sum == target){
                int[] temp = new int[j-i];
                for(int k=0; k<j-i; k++){
                    temp[k] = k+i;
                }
                result.add(temp);
            }
        }*/
        //双指针优化
        for(int l=1,r=2; l<r; ){
            int sum = (l + r) * (r - l + 1) / 2;
            if (sum == target){
                int[] temp = new int[r-l+1];
                for (int i = l; i <= r; ++i) temp[i-l] = i;
                result.add(temp);
                l++;
            }
            else if (sum < target) r++;
            else l++;

        }
        return result.toArray(new int[result.size()][]);
    }
}

LeetCode.994 腐烂的橘子

  • 广度遍历即可(使用队列)
  • 每分钟每个腐烂的橘子(2)都会使其上下左右的新鲜橘子(1)腐烂.
  • 第一个腐烂的橘子在第一个网格(0,0),所以只让其上下左右的新鲜橘子入队。
  • 用 minute 标记腐烂时间,并让新鲜橘子(1)变为腐烂的橘子(2)
  • 用 minute 记录腐烂的持续时间,每一层的橘子在内一层的橘子的腐烂时间基础之上自增 1,代表时间过了 1 分钟。
  • 最后检查网格中是否还有新鲜的橘子
    有,返回 -1 代表 impossible。
    没有则返回 minute。
在给定的网格中,每个单元格可以有以下三个值之一:
值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 {
    int[][] dir = { {-1,0},{1,0},{0,-1},{0,1} };
    class Node{
        int x;
        int y;
        int minute;
        Node(int x, int y, int minute){
            this.x = x;
            this.y = y;
            this.minute = minute;
        }
    }
    public int orangesRotting(int[][] grid) {
        int rows = grid.length;
        int clunms = grid[0].length;
        int minute = 0;
        Queue<Node> queue = new LinkedList<>();

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < clunms; j++)
            if (grid[i][j] == 2)
                queue.add(new Node(i, j, minute));
        }
        while (!queue.isEmpty()) {
            Node node = queue.poll();
            minute = node.minute;
            for (int k = 0; k < 4; k++) {   //一个腐烂,四周受害
                int newX = node.x + dir[k][0];
                int newY = node.y + dir[k][1];
                if (newX >= 0 && newX < rows && newY >= 0 && newY < clunms && grid[newX][newY] == 1) {
                    grid[newX][newY] = 2;  //标记腐烂
                    queue.add(new Node(newX, newY, node.minute + 1)); //腐烂周期+1
                }
            }
        }
        //check for fresh oranges
        for(int[] row : grid) {
            for (int i : row)
                if (i == 1) return -1;
        }
        return minute;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容