LeetCode简单入门类型算法解析(一)

LeetCode 20.有效的括号
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。

有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

示例 1:
输入: “()”
输出: true

示例 2:
输入: “()[]{}”
输出: true

思路:利用栈先进后出的特性来解决这道题;先建立一个栈,把左边括号全部压入栈,然后再对右边括号进行判断是否出栈操作(栈不为空和括号匹配就出栈);要是全匹配最后判定栈空返回true。
具体代码如下;

class Solution {
    public boolean isValid(String str) {
        Stack s = new Stack();		//建立栈
                for (int i = 0; i < str.length(); i++) {  
                    char c = str.charAt(i);
                    switch (c) {
                        case '{':
                        case '[':
                        case '(':
                            s.push(new Integer(c));		//把左边括号压栈
                            break;
                        case '}':
                            if (!s.isEmpty() && ((Integer) s.pop()) == '{')	//判断是否匹配
                                break;
                            else return false;
                        case ']':
                            if (!s.isEmpty() && ((Integer) s.pop()) == '[')	//判断是否匹配
                                break;
                            else return false;
                        case ')':
                            if (!s.isEmpty() && ((Integer) s.pop())== '(')	//判断是否匹配
                                break;
                            else return false;
                    }
                }
                if (s.isEmpty()) return true;	//栈空说明所有括号匹配
                else return false;
    }
}

LeetCode1.两数之和

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

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

示例:

给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

思路:利用HashMap把数组的下标和值以Key-Value(数组下标是Value)的形式保存。先建立一个只有两个值的数组(res)用于保存最后的答案;建立一个for迭代来得到数组里的所有值;用target值减去当前数组(nums)的值会得到另一个需要的值(Map里的Key);接下来就判断Map里面是否包含这个这个Key;包含的话就把这个键所包含的值(数组的下标)赋给res【0】;把这个循环的I赋给热水【1】;最后返回res。

代码如下:

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer,Integer> map = new HashMap<>();//建立hash表
        int[] res = new int[2];//建立一个拥有两个值的数组用于存放答案
        for (int i = 0; i < nums.length; i++) {
            int dif = target - nums[i];//dif是除nums是【i】的另一个值
            if (map.containsKey(dif)) {//判断是否包含这个Key
                res[0] = map.get(dif);//得到数组下标1
                res[1] = i;//得到数组下标2
                return res;
            }
            map.put(nums[i],i);
        }
        return res;
    }
}

LeetCode101 对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/
2 2
/ \ /
3 4 4 3

但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1
/
2 2
\
3 3
思路:本题思路是建立一个将树的左右子树进行交换过后的树,然后递归的将原树的左子树跟新树的右子树进行比较,原树的右子树跟新树的左子树比较;如果完全相等则说明原树是镜像对称的。
代码如下:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        return isMirro(root,root);
    }
    
    public boolean isMirro(TreeNode t1,TreeNode t2){
        if(t1 == null && t2 == null) return true;//空树不做计较
        if(t1 == null || t2 == null) return false;//残缺的树返回false
        //递归的将两树进行比较;原树的左子树跟新树的右子树进行比较,原树的右子树跟新树的左子树比较
        return (t1.val == t2.val)&&isMirro(t1.left,t2.right)&&isMirro(t1.right,t2.left);
    }
}

LeetCode136 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

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

思路:使用异或运算符(^)来达到目的;此运算符用来判断两个操作数是否相同,相同返回true,不同返回false。(一个值和0进行按位异或操作所得为该值,相同的两个值进行异或操作,所得为0)
代码如下:

class Solution {
    public int singleNumber(int[] nums) {
            int ans = nums[0];
            if (nums.length > 1) {
                for (int i = 1; i < nums.length; i++) {
                    ans = ans ^ nums[i];
                }
            }
 return ans;
        }
    }

LeetCode189 旋转数组
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
示例 1:

输入: [1,2,3,4,5,6,7] 和 k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右旋转 1 步: [7,1,2,3,4,5,6]
向右旋转 2 步: [6,7,1,2,3,4,5]
向右旋转 3 步: [5,6,7,1,2,3,4]

思路:定义一个新数组运用for迭代进行逐步代换,利用公式(i+k)%数组长度 来算出具体代换位置,然后将新数组的值赋予原数组。

代码如下:

class Solution {
        public void rotate(int[] nums, int k) {
            int arr[] = new int[nums.length];
            for (int i = 0;i<nums.length;i++)
            {
                arr[(i+k)%nums.length] = nums[i];
            }
            for (int i = 0; i<nums.length;i++)
            {
                nums[i] = arr[i];
            }
        }
            }

LeetCode206 反转链表
反转一个单链表。
示例:

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

思路:建立一个新的节点(new),和一个临时节点(tem),以及cur(当前节点);把头结点保存的指针给临时节点(以免和下一个节点失联);接着将当前节点指向新节点,这样就完成了一个链表的反转,接下来运用循环来完成剩下的节点就行。

代码如下:

/**
 * 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 new = null;
            ListNode cur = head;//此时头结点是当前需要操作的节点
            ListNode tem = null;
            while(cur != null)
            {
            tem = cur.next;   //把当前节点保存的下一个节点的地址给临时节点
            cur.next = new;	  //当前节点指向新节点
            new = cur;	//当前节点已经完成反转指向,由于后面一个节点还没完成反转指向所以当前节点换为新节点
            cur = tem;//由于前一个节点已近换位,此节点也后退一次
            }
            return new;
        }
        }

LeetCood 234 回文链表
判断一个链表是否为回文链表。
示例 1:

输入: 1->2
输出: false

示例 2:

输入: 1->2->2->1
输出: true

思路:运用快慢指针的思路。创建快慢指针(慢指针走一步快指针走两步,快指针到达终点慢指针刚好走到一半),将链表从中间一分为二,反转后半段链表,开始比较两段链表的值是否相等。

代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
        public boolean isPalindrome(ListNode head) {
            //当链表为空或为一个的时候不做判断
            while(head == null||head.next == null )
                return true;
            //创建快慢指针
            ListNode p = new ListNode(-1);
            p.next = head;
            ListNode fast = p;
            ListNode slow = p;
            //指针开跑 快指针跑两步慢指针跑一步 快指针到达终点慢指针刚好走一半
        while(fast != null && fast.next != null)
        {
            slow = slow.next;
            fast = fast.next.next;
        }
        //快指针指向后半段链表的起始点,断开链表,将前半段指针指向起始位置
        fast = slow.next;
        slow.next = null;
        slow = p.next;
        //链表反转
            ListNode pre = null;
            ListNode cur = fast;
            ListNode tem = null;
            while(cur != null)
            {
                tem = cur.next;
                cur.next = pre;
                pre = cur;
                cur = tem;
            }
            //逐一判断回文链表值是否相等
        while (pre != null)
        {
            if (slow.val != pre.val)
            {
                return false;
            }
            slow = slow.next;
            pre = pre.next;
        }
        return true;
        }

        }

LeetCood283 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:

必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。

思路:运用for迭代遍历数组值,当遇到零时将后一个数补上并统计有多少个空位最后再把零补上。

代码如下:

class Solution {
    public void moveZeroes(int[] nums) {
        int i = 0;
        for(int j = 0; j < nums.length; j++){
            if(nums[j] != 0){
                if(i != j){
                    nums[i] = nums[j];
                }
                i ++;
            }
        }
        for(; i < nums.length; i++){
            nums[i] = 0;
        }
    }
}

LeetCood 155 最小栈
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。

push(x) – 将元素 x 推入栈中。
pop() – 删除栈顶的元素。
top() – 获取栈顶元素。
getMin() – 检索栈中的最小元素。
示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.

思路:创建两个站栈(一个辅助栈一个最小栈),push操作:辅助栈直接压入所有值,最小栈进行判断(栈空或者当前值小于最小栈栈顶值则压入栈),pop操作:当辅助栈值等于最小栈值时执行pio操作;top操作:返回辅助栈顶值;检索最小栈方法:返回最小栈顶值。

代码如下:

class MinStack {
    private Stack<Integer> stack;
    private Stack<Integer> minstack;
    /** initialize your data structure here. */
    public MinStack() {
        stack = new Stack<>();
        minstack = new Stack<>();
    }

    public void push(int x) {
        stack.push(x);
        if (minstack.isEmpty() ||x<=minstack.peek())//需要栈空或者当前值小于最小栈栈顶值则压入栈
            minstack.push(x);
    }

    public void pop() {
        if (stack.pop().equals(minstack.peek()))//当辅助栈值等于最小栈值时执行pio操作
            minstack.pop();

    }

    public int top() {
        return stack.peek();
    }

    public int getMin() {
        return minstack.peek();
    }
}
/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

LeetCood 53 最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

思路:首先定义一个int数等于数组的第一个值,再定义一个sum累加值,利用for迭代去完成这个累加得过程,当遇到累加值为负数的时候便放弃当前的累加值并让sum等于次迭代数继续累加,最后sum与ans’进行比较较大的数胜出。

代码如下;

class Solution {
    public int maxSubArray(int[] nums) {
        int ans = nums[0];
        int sum = 0;
        for (int a: nums) {
            if (sum > 0)
                sum += a;
            else {
                sum = a;
            }
            ans = Math.max(ans,sum);
        }
            return ans;
    }
}

LeetCode 104 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。

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

3

/
9 20
/
15 7
返回它的最大深度 3 。

思路:此题采用递归的方法比较根节点以下的所有子树的深度,递归临界点是数空,即root为空。

代码如下:

/**
 * 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;
            return Math.max(maxDepth(root.left),maxDepth(root.right))+1;
    }
}

LeetCood 169 求众数
给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在众数。

示例 1:

输入: [3,2,3]
输出: 3
示例 2:

输入: [2,2,1,1,1,2,2]

思路1:排序思路,先将数组排序后直接返回数组n/2下标处的值即为众数值。
思路二:利用栈(消消乐思想)在入栈时进行判断(栈空或者跟栈顶元素比较相等时入栈,反之栈顶元素出栈),最后剩下的就是众数。

思路一代码如下:

class Solution {
    public int majorityElement(int[] nums) {
       Arrays.sort(nums);
        return nums[nums.length/2];
        
    }
}

思路二代码如下:

class Solution {
    public int majorityElement(int[] nums) {
       ArrayDeque <Integer>s = new ArrayDeque<>();
        for (int num:nums) {
            if (s.isEmpty()||num == s.peek())
            {
                s.push(num);
            }else
                s.pop();
        }
        return s.peek();
    }
}

LeetCood 198 打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。

思路:采用动态规划的思想(当前状态的最优解由之前某几个状态的最优解得到而不关心他的得到方式),本题需要求出dp方程max(dp[i-1], dp[i-2] + nums[i-1]),然后通过迭代的方式遍历完数组求出最终解。

代码如下:

class Solution {
    public int rob(int[] nums) {
        if(nums.length == 0)
            return 0;
        int[] dp = new int[nums.length + 1];
        dp[0] = 0;
        dp[1] = nums[0];
        for(int i = 2; i <= nums.length; i++) {
            dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i-1]);
        }
        return dp[nums.length];
    }
}

LeetCode 237 删除链表中的节点
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
示例 1:

输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.

说明:
链表至少包含两个节点。
链表中所有节点的值都是唯一的。
给定的节点为非末尾节点并且一定是链表中的一个有效节点。
不要从你的函数中返回任何结果。

思路:删除其中一个节点就需要把当前节点指向被删除节点的后一个节点。

代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public void deleteNode(ListNode node) {
        node.val = node.next.val;
        node.next = node.next.next;
    }
}

LeetCode 217 存在重复元素
给定一个整数数组,判断是否存在重复元素。
如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。

示例 1:

输入: [1,2,3,1]
输出: true
示例 2:

输入: [1,2,3,4]
输出: false

思路:建立一个哈希表,运用迭代判断新加入的元素是否存在于哈希表,存在就返回true,遍历完成都没相同的元素就返回false。

代码如下:

class Solution {
    public boolean containsDuplicate(int[] nums) {
        HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
        for(int i = 0; i < nums.length; i++){
            if(map.containsKey(nums[i]))
                return true;
            else
                map.put(nums[i], 1);
        }
        return false;
    }
}

LeetCode 70 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。

  1. 1 阶 + 1 阶
  2. 2 阶

思路:运用迭代斐波拉切数列来解决此题。

代码如下:

class Solution {
    public int climbStairs(int n) {
        if (n == 1||n == 2)
        {return n;}
        int a = 1,b = 2;
        int c = 0;
        for (int i = 3;i<=n;i++)
        {
             c = a+b;
            a =b;
            b=c;
        }
        return c;
    }
}

你可能感兴趣的:(LeetCode简单入门类型算法解析(一))