前言
刷题更让我们对一门语言有更加深入的理解,也可以增进对数据结构的理解,百里无一害。
Two Sum
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
1 | Given nums = [2, 7, 11, 15], target = 9, |
这也是我处女面试的第一个算法,当时想的方法是最暴力的方法,直接两个循环完事,但是时间复杂度是$O(n^{2})$,那是相当的高o(╥﹏╥)o。后来想了一下找到了一个简单的方法,当时由于太紧张写的不太好。当时的问题方法也稍微有点不同,当时要求的是找到相对应的数字,不是index。 先回顾一下当时的算法:
1 | int[] another(int[] nums, int target) { |
当时想到的是两头同时遍历的方法,但是有个前提要求就是list必须是排过序的,当nums
无限大时排序所消耗的时间可以忽略的,这个方法有点类似于binary search。我当时也想过用HashMap
,好像处于什么原因被面试官否定了,whatever不重要的。不闲扯了,我们开始看这题的比较优化的算法,时间复杂度是O(n)
。
1 | int[] twoSum(int[] nums, int target) { |
算法思路:
- 因为是用的
HashMap
所以在检测key是否contain的话使用的是hash的方法,所以复杂度是$O(1)$ - 第7-11行,是来判断这个HashMap是否包含这个num,如果这个num不包含在HashMap里面,然后把该num存到HashMap里面,num当做key,index当做value。这样就相当于把访问过的num和num的index存到HashMap里面,然后再遍历nums的时候得对每个数可以得到一个差值,然后判断这个差值是否存在HashMap里面,如果存在就代表得到这个结果了,如果不存在就把这个
nums[i]
存到HashMap。
Add Two Numbers
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example:
1 | Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) |
算法思想:
主要应该考虑一下边界情况:
- 当sum>=10
- 两个链表不一样长
- 在最后一个数字相加的时候sum>=10
第6行的while语句就是为了两条链表不一样长度。第7-8行判断如果该链表不为null就取该val,不然的话就为0(为了不影响下面的计算)。int overflow = 0
是为了解决和超过10的情况,第9行把溢出的数字和v1,v2相加,然后把该结果取余就是结果。然后把overflow = sum/10
得到进位数。每次生成新的数字之后生成一个新的node没然后链接起来。主要是考虑不同的边界情况。
1 | public ListNode addTwoNumbers(ListNode l1, ListNode l2) { |
Longest Substring Without Repeating Characters
Given a string, find the length of the longest substring without repeating characters.
Example 1:
1 | Input: "abcabcbb" |
Example 2:
1 | Input: "bbbbb" |
Example 3:
1 | Input: "pwwkew" |
解题方法&思路:
首先说下题意,我刚开始是没理解题意来得(暴露了自己的无知╮(╯▽╰)╭),题意就是匹配到最长的子字符串,并且不能重复。比如pwwkew
可以匹配到wke
最后一个w不可以被匹配到,因为该子字符串已经包含了一个w。
算法解析:我们可以使用暴力解法:双循环(但是不推荐)。我们可以使用HashMap来解决该问题,因为HashMap查询的时候只需要$O(1)$的时间复杂度。
- 首先对该字符串进行遍历,如果该字符不在HashMap里面,则把该字符添加到HashMap,取max(HashMap length, ans)
- 如果该字符已经出现在HashMap里面,从HashMap里面去除一个字符,然后current index保持不变(会对该index进行再次遍历)
- 循环
有点类似于:当一个字符不在该HashMap,push进去,如果已经在了,pop出来。然后在push之后计算最大的长度是多少。(进去一个如果已经存在就pop出来一个,因为重点是长度,所以不需要关心到底是哪些字符)。
Python伪代码
1 | def LongSubString(s): |
Java解决方法:
1 | import java.util.HashMap; |
Valid Parentheses
Given a string containing just the characters '('
, ')'
, '{'
, '}'
, '['
and ']'
, determine if the input string is valid.
An input string is valid if:
- Open brackets must be closed by the same type of brackets.
- Open brackets must be closed in the correct order.
Note that an empty string is also considered valid.
Example 1:
1 | Input: "()" |
Example 2:
1 | Input: "()[]{}" |
Example 3:
1 | Input: "(]" |
Example 4:
1 | Input: "([)]" |
Example 5:
1 | Input: "{[]}" |
解题思路:
这个题我使用了stack(栈)的方法来解决这个问题。stack是一种先进后出的数据结构,所以更加适合这种问题。
- 我们先来初始化一个HashMap来存相对应的括号
- 先判断该HashMap是否存在该左括号,如果存在就把左括号push到stack里面,
- 如果不存在先判断stack是否有数据(因为不存在的情况只有该字符是右括号的情况)
- 然后根据stack pop出来的结果在HashMap找到相对应的右括号,然后判断该字符和HashMap里面的右括号是否匹配。
1 | public boolean isValid(String s) { |
Reverse Integer
Given a 32-bit signed integer, reverse digits of an integer.
Example 1:
1 | Input: 123 |
Example 2:
1 | Input: -123 |
Example 3:
1 | Input: 120 |
本来以为这个题很简单,使用了最简单的算法,但是呢,出现了一个整型溢出的问题o(╥﹏╥)o。
先解析一下思路吧:
- 首先我们可以用
x%10
来得到最后一个数字(因为数字不可能大于10) x/10
是把最后一位数去掉reverse*10
是为了整体向左移一位,比如(44, 44*10 = 440)多出一个空位,然后加上x%10
的数字
1 | public int reverse(int x) { |
这样如果数字区间在$[−2^{31}, 2^{31} − 1]$的话那么就会出现溢出的问题了,大家可以使用1534236469
来尝试一下。
所以这时候我们就需要来做些判断了:
当reverse > intMAX/10
的时候我们基本上就可以确定他会溢出了,比如说intMAX = 2147483647
,假设我们的reverse = 214748365
这时候intMAX/10 =214748364
,reverse > intMAX
。这时候如果reverse * 10
我们不管最后一个数字是什么了,reverse
已经超出了int取值范围。
正确代码:
1 | public int reverse(int x) { |
Palindrome Number
Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.
Example 1:
1 | Input: 121 |
Example 2:
1 | Input: -121 |
Example 3:
1 | Input: 10 |
回文数也就是说该数字等于翻转后的数字,num = reverse(num)
。首先我们可以确定如果该数字是负数直接false就好了。我们可以使用上一题的思路,把数字翻转然后看是否相等。也可以把边界情况考虑进行。
1 | public boolean isPalindrome(int x) { |
Longest Common Prefix
Write a function to find the longest common prefix string amongst an array of strings.
If there is no common prefix, return an empty string ""
.
Example 1:
1 | Input: ["flower","flow","flight"] |
Example 2:
1 | Input: ["dog","racecar","car"] |
Note:
All given inputs are in lowercase letters a-z
.
集体思路:
采用了垂直对比法。比如:
1 | s1 = 'flower' |
1 | public String longestCommonPrefix(String[] strs) { |
也可以试着得到最短的string,然后进行循环,思路差不多:
这种情况其实没什么必要,因为可能没循环结束就return了。
1 | public String longestCommonPrefix(String[] strs) { |
Merge Two Sorted Lists
Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.
Example:
1 | Input: 1->2->4, 1->3->4 |
这个好像没什么说的,就直接对比大小然后merge在一起就行
1 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { |
Remove Duplicates from Sorted Array
Remove Duplicates from Sorted Array
Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
Example 1:
1 | Given nums = [1,1,2], |
Example 2:
1 | Given nums = [0,0,1,1,1,2,2,3,3,4], |
最获取长度的同时需要对array内部数据进行修改:
通过每次记录num,如果不相同的话,对数组的其实位置开始修改,然后curr是正在修改的index。(也会随着i增加而增加,如果所有数字都不一样)只不过是重新赋值了一次而已。
1 | public int removeDuplicates(int[] nums) { |
Roman to Integer
Roman numerals are represented by seven different symbols: I
, V
, X
, L
, C
, D
and M
.
1 | Symbol Value |
For example, two is written as II
in Roman numeral, just two one’s added together. Twelve is written as, XII
, which is simply X
+ II
. The number twenty seven is written as XXVII
, which is XX
+ V
+ II
.
Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII
. Instead, the number four is written as IV
. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX
. There are six instances where subtraction is used:
I
can be placed beforeV
(5) andX
(10) to make 4 and 9.X
can be placed beforeL
(50) andC
(100) to make 40 and 90.C
can be placed beforeD
(500) andM
(1000) to make 400 and 900.
Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999.
Example 1:
1 | Input: "III" |
Example 2:
1 | Input: "IV" |
Example 3:
1 | Input: "IX" |
Example 4:
1 | Input: "LVIII" |
Example 5:
1 | Input: "MCMXCIV" |
好像没什么好说的就是简单的字符串操作而已:
1 | public int romanToInt(String s) { |
Remove Element
Given an array nums and a value val, remove all instances of that value in-place and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
The order of elements can be changed. It doesn’t matter what you leave beyond the new length.
Example 1:
1 | Given nums = [3,2,2,3], val = 3, |
Example 2:
1 | Given nums = [0,1,2,2,3,0,4,2], val = 2, |
这个和前面那个remove duplicate number是一个思路:
这个算法很简单,但是效率贼高。其实很好理解,就是当这个数字不等于val的时候,会用之前的curr(非重复的数字坐标)来替换当前的val。
1 | 3, 2, 2, 3 & val = 2 |
1 | public int removeElement(int[] nums, int val) { |
Implement strStr()
Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
Example 1:
1 | Input: haystack = "hello", needle = "ll" |
Example 2:
1 | Input: haystack = "aaaaa", needle = "bba" |
返回要求的是index,我还以为是长度一度迷茫为啥不对o(╥﹏╥)o,一个for就能解决的问题,我们先去needle
的第一个字符,然后在循环haystack
的时候如果里面有字符和needle
的第一个字符匹配了就用substring
来接取相对应的长度,然后判断是否和needle
相等(需要判断index的长度是不是超过了haystack
的长度)。
1 | public int strStr(String haystack, String needle) { |
Search insert position
Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You may assume no duplicates in the array.
Example 1:
1 | Input: [1,3,5,6], 5 |
Example 2:
1 | Input: [1,3,5,6], 2 |
就是找到合适的位置,然后返回相对应的index,没什么难度:
1 | public int searchInsert(int[] nums, int target) { |
Median of two sorted array
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
You may assume nums1 and nums2 cannot be both empty.
Example 1:
1 | nums1 = [1, 3] |
Example 2:
1 | nums1 = [1, 2] |
没办法太菜了找不到合适的方法来写了,有想过分开循环,但是这样需要有很多的判断条件,晚会会再尝试的,目前就快的方法就是合并array了。
1 | public double findMedianSortedArrays(int[] nums1, int[] nums2) { |
String to Integer (atoi)
Implement atoi
which converts a string to an integer.
The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.
The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.
If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.
If no valid conversion could be performed, a zero value is returned.
Note:
- Only the space character
' '
is considered as whitespace character. - Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231, 231 − 1]. If the numerical value is out of the range of representable values, INT_MAX (231 − 1) or INT_MIN (−231) is returned.
Example 1:
1 | Input: "42" |
Example 2:
1 | Input: " -42" |
Example 3:
1 | Input: "4193 with words" |
Example 4:
1 | Input: "words and 987" |
Example 5:
1 | Input: "-91283472332" |
这是我写LeetCode以来submit最多的次数╮(╯▽╰)╭,里面条件的限制和符号的判定太烦了。给大家写一下判断条件:
- 空格只能出现在最前面,一旦出现了-+0-9这些符号,之后再遇到空格就要break
- -+符号考虑到符号的问题
- 只能以数字开头的才能提取数字,如果不是就return 0
- 考虑到整型溢出的问题
就是判断条件有点麻烦,其他的还好,我写的有点乱七八糟的,讲究看下。。。如果有好的idea可以写在comment里面,我会修改的。
1 | public int myAtoi(String str) { |
Container With Most Water
本来觉得是要用动态规划,可是看了大佬的代码和idea瞬间觉得自己的思路是错的。这个题其实就是变相的求最大面积,我们可以知道长方体的面积是长*高,在遍历这个list的时候长度是一直在减小的,如果长度变小我们只有找到更大的高度才能使面积最大。那么我们可以从两头同时开始遍历,如果left < right
那么left向左移,因为我们要找到higher height,如果left >= right
right向左移就行了。这样就会找到最大的area。
ps:不想想太复杂,试着从最基本的信息去推断,比如这个面积,如果一个变量变下,那另一个变量只有变大才能找到最大的。(😁学习到了)
1 | public int maxArea(int[] height) { |
Merge Sorted Array
Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.
Note:
- The number of elements initialized in nums1 and nums2 are m and n respectively.
- You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2.
Example:
1 | Input: |
这是我今天逛牛客的时候发现的一道题,然后想了一下,按照我现在的思想好像只知道直接merge然后sort。还有一种就是正序插入,但是每个element都需要后移一位,但是这样的效率太低了,看了网上的大神的idea之后就发现了新大陆。因为这个list是拍过序的,那么我们就知道了最后一个元素肯定是最大。那么我们为什么不从后面往前面循环呢,这样不需要元素以为,只需要直接赋值就好了。
1 | public void merge(int[] nums1, int m, int[] nums2, int n) { |
Single Number
Given a non-empty array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
Example 1:
1 | Input: [2,2,1] |
Example 2:
1 | Input: [4,1,2,1,2] |
庆幸一下终于可以独立思考出来一些简单的算法了。这个题其实算是还OK的,可以使用HashMap解决,因为HashMap监测key的时候的时间复杂度是$O(1)$,所以整体时间是$O(n)$。在loop里面去判断该数字是否存在HashMap里面,如果不存在就push进去,如果已经存在就删除。那么最后剩下的那个元素肯定是single(单身狗)。
1 | public int singleNumber (int[] A) { |
Ps: 在discuss里面看到了一个特别骚的操作。。。真的骚操作。。。
使用了异或(exclusive OR简称xor)这个来判断的,异或的话空间复杂度只有$O(1)$。
$1\oplus0=1$
$1\oplus1=1$
$0\oplus0=0$
$0\oplus1=1$
1 | public int singleNumber(int[] nums) { |
行吧。。。牛逼。。
Remove Nth Node From End of List
Remove Nth Node From End of List
Given a linked list, remove the n-th node from the end of list and return its head.
Example:
1 | Given linked list: 1->2->3->4->5, and n = 2. |
Note:
Given n will always be valid.
Follow up:
Could you do this in one pass?
解析:
题意就是删除倒数第N的节点。这个可以使用一个快慢指针的方法来解决,先让快的指针移动n个node,然后慢的指针开始移动。这样当快的指针为null的时候,慢的指针刚好就是要删除的节点。
其实可以当fast.next == null
的时候就停止。这样slow.next = slow.next.next
是一样的,因为我的代码用了curr
来判断是否为null(删除的元素是不是head)
1 | public class ListNode { |
Maximum Subarray
Given an integer array nums
, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
Example:
1 | Input: [-2,1,-3,4,-1,2,1,-5,4], |
Follow up:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
题意解析:找到和最大的子序列。
算法解析:
可以使用动态规划来做。初始化一个数组长度和原数组一样,如果i-1
的数字小于零就表示这就不用需要进行加和,因为加负数就是在减小,然后把i
就行赋值。在每次循环的时候找到最大的值就行(max
,dp[i]
取最大的)。dp[i]
存的结果:如果dp[i-1]
小于零那就是本身,不然就是dp[i-1] + num[i]
加上当前数字。
1 | public int maxSubArray(int[] nums) { |
看了大佬的思路之后发现了新天地,可以节省一些内存空间,降低空间复杂度:
只需要两个空间的位置就行了,因为我们只需要i
和i-1
这两个参数。
1 | public int maxSubArray(int[] nums) { |
Climbing Stairs
You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Note: Given n will be a positive integer.
Example 1:
1 | Input: 2 |
Example 2:
1 | Input: 3 |
这是一个很经典的动态规划的问题。一次可以走一阶楼梯或者两阶楼梯。在第一层的时候肯定只能上一阶,第二层的时候可以是1+1(连续走两个一阶)或者2(直接两阶)所以是两种方法,第三层的时候可以是1+1+1, 1+2, 2+1三种方法。所以可以看出$f(n)=f(n-1)+f(n-2)$的算法。
1 | public int climbStairs(int n) { |
Best Time to Buy and Sell Stock
Best Time to Buy and Sell Stock
Say you have an array for which the ith element is the price of a given stock on day i.
If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.
Note that you cannot sell a stock before you buy one.
Example 1:
1 | Input: [7,1,5,3,6,4] |
Example 2:
1 | Input: [7,6,4,3,1] |
这个题的思路稍微简单一点,可以使用动态规划来找到最小的买入价格,然后我们就可以根绝在买入价格最低的日期之后,找到卖出价格最高的点,这样收益就是最大的。
1 | public int maxProfit(int[] prices) { |
Linked List Cycle
Given a linked list, determine if it has a cycle in it.
To represent a cycle in the given linked list, we use an integer pos
which represents the position (0-indexed) in the linked list where tail connects to. If pos
is -1
, then there is no cycle in the linked list.
算法思路:
一开始想到的是用HashMap的方式来解决这个问题,但是这样的话空间复杂度就高了很多就是$O(n)$了,然后看了一下大神们的解法,就是利用快慢指针的方法,两种我都试了一下:
- HashMap的方法
1 | public boolean hasCycle(ListNode head) { |
快慢指针的方法
这样效率高,内存占用少
1 | public boolean hasCycle(ListNode head) { |
Find First and Last Position of Element in Sorted Array
Find First and Last Position of Element in Sorted Array
Given an array of integers nums
sorted in ascending order, find the starting and ending position of a given target
value.
Your algorithm’s runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1]
.
Example 1:
1 | Input: nums = [5,7,7,8,8,10], target = 8 |
Example 2:
1 | Input: nums = [5,7,7,8,8,10], target = 6 |
使用了一个二分查找法,头尾遍历法,不过貌似时间复杂度有点高。。没有别人那么快,花了1ms才通过。一会准备去看看大神的思路,看看有没有好的idea。第23-28行的主要作用是考虑到起始位置和结束位置在同一个地方,当其中有任何一个数字不是-1的时候,代表已经找到这个数字了,但是head==tail
的时候就会结束循环了,所以会进行一个判断。
1 | public int[] searchRange(int[] nums, int target) { |
刚去看了一下discussion里面,然后发现自己写的二分查找不叫二分查找,只能算是一个两头遍历的循环。然后根据二分查找的方法写了一份:
1 | public int[] searchRange(int[] nums, int target) { |
Pow(x, n)
Implement pow(x, n), which calculates x raised to the power n (xn).
Example 1:
1 | Input: 2.00000, 10 |
Example 2:
1 | Input: 2.10000, 3 |
Example 3:
1 | Input: 2.00000, -2 |
Note:
- -100.0 < x < 100.0
- n is a 32-bit signed integer, within the range [−231, 231 − 1]
这个就是简单的求一下平方,然后给保留5位小数就行了,用Python简单的写了一波
1 | class Solution(object): |
Intersection of Two Linked Lists
Intersection of Two Linked Lists
也算是我第一次面试的第一道题。当时想的是暴力解决,double循环哈哈哈。这次写的时候想到了一个新的方法就是使用HashMap来解决,最坏的情况是$O(n+m)$,不过也比$O(n^2)$好。先把一个LinkList全部放到HashMap里面,然后循环第二个链表,看是不是有一样的node,如果有就直接return当前的node,如果直到循环结束还没有就return null
1 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) { |
在面试的时候面试官也给我说了另一种解法,就是假设已知两条链表的长度,然后先把两条链表截取到一样的长度,然后一个循环就能找到相对应的结果。这个我觉得时间复杂度比我的要高,就没写。
Majority Element
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋
times.
You may assume that the array is non-empty and the majority element always exist in the array.
Example 1:
1 | Input: [3,2,3] |
Example 2:
1 | Input: [2,2,1,1,1,2,2] |
看到这一类的题,最先想到的就是使用HashMap来解决这个计数的问题,当计数的结果> nums.leng/2
的时候可以直接return就好了,准没错
1 | public int majorityElement(int[] nums) { |
然后看了一下官方的解法,就是先sort一下,如果该数字的个数大于总array长度的一般也就意味着sort完之后取中间那个数字准没错。。。那么简单的方法咋就没想到呢o(╥﹏╥)o
1 | public int majorityElement(int[] nums) { |
Min Stack
Min Stack(https://leetcode.com/problems/min-stack/)
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
- push(x) – Push element x onto stack.
- pop() – Removes the element on top of the stack.
- top() – Get the top element.
- getMin() – Retrieve the minimum element in the stack.
Example 1:
1 | Input |
这个只需要知道stack是先进后出的原则就行。
1 | import java.util.Collections; |
Reverse Linked List
Reverse a singly linked list.
Example:
1 | Input: 1->2->3->4->5->NULL |
翻转链表可以循环实现,也可以用递归实现。
1 | public ListNode reverseList(ListNode head) { |
然后递归的话就刚开始看可能不是特别好理解的。总感觉遇到递归就有点懵逼的感觉。。。
1 | public ListNode reverseList(ListNode head) { |
Palindrome Linked List
Given a singly linked list, determine if it is a palindrome.
Example 1:
1 | Input: 1->2 |
Example 2:
1 | Input: 1->2->2->1 |
Follow up:
Could you do it in O(n) time and O(1) space?
思路:
本来想的是用递归的方法算一下和,如果是回文的话结果应该是一样的,想法很美好,现实很残酷。。。LeetCode官方应该也考虑到这个问题了,如果算sum的话会导致整型溢出的问题。。。。不过也算是一个思路吧。o(╥﹏╥)o
1 | public boolean isPalindrome(ListNode head) { |
最近遇到的题不是递归就是动态规划。。。看来这块有点薄弱,有时间要多练习一下。。看了discussion里面,有个大神写的也是递归的方法,类似于先把第一个指针走到结尾,第二个指针指向head,然后对比是不是一样。感觉很牛逼。。不过递归貌似花费时间有点久。
1 | boolean flag = true; |
Ps: 还有一种快慢指针的方法。。就是走到中间,然后把两条链表分开对比就行了,但是感觉有点麻烦,还是不写了。。。
Move Zeroes
Given an array nums
, write a function to move all 0
‘s to the end of it while maintaining the relative order of the non-zero elements.
Example:
1 | Input: [0,1,0,3,12] |
Note:
- You must do this in-place without making a copy of the array.
- Minimize the total number of operations.
一开始看到这个想了一下双指针,一个从头开始一个从尾部开始,这样虽然可以把0都放到后面,但是这样就不是顺序来的了。。。看了一下大佬思路,也是双指针(方法思路没错对吧),只不过这个双指针都是从头开始的。先设置一个0的指针zero=-1
因为我们一开始不知道0的位置在那,然后开始循环,如果该数字为0可以对zero
进行赋值了(zero == -1
),当zero != -1
说明之前已经有了0的数字。然后如果该数字不等于0的时候表示可以对之前的zero的index进行替换,前提是zero != -1
,然后判断zero和i的位置,如果i是zero的next说明是只有一个zero,不然的话就代表zero后面还是一个0的数字,所以这时候zero++
就行。
1 | public void moveZeroes(int[] nums) { |
Find All Numbers Disappeared in an Array
Find All Numbers Disappeared in an Array
Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once.
Find all the elements of [1, n] inclusive that do not appear in this array.
Could you do it without extra space and in O(n) runtime? You may assume the returned list does not count as extra space.
Example:
1 | Input: |
题解:数组长度1-n,要判断数组里面出现的数字是不是在1-n之间,如果少了哪个数字就给补上。
比如:[2,2]
数组长度1-2
,那么改数组少了1。
solution 1:
刚开始考虑的是先sort一下,然后判断index在0,末尾和中间的情况进行补全,但是貌似有点浪费时间了。。所以时间复杂度有点高$O(nlog_{n} + n)$。不过也算是一种方法对吧。。。o(╥﹏╥)o
1 | public List<Integer> findDisappearedNumbers(int[] nums) { |
solution 2:
看了一下discussion感觉他们写的方法屌爆了。。。因为数组里面的数字是在数组长度1-n
之内的,所以这个时候我们可以做一个指示器的格式,把数组里面每个数字所对应的坐标变成负数,然后再寻找一个array里面哪些是负数。很欢喜。。
1 | public List<Integer> findDisappearedNumbers(int[] nums) { |
Word Ladder
126 题
Given two words (beginWord and endWord), and a dictionary’s word list, find the length of shortest transformation sequence from beginWord to endWord, such that:
- Only one letter can be changed at a time.
- Each transformed word must exist in the word list.
Note:
- Return 0 if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
- You may assume no duplicates in the word list.
- You may assume beginWord and endWord are non-empty and are not the same.
Example 1:
1 | Input: |
词语接龙,一个老外很喜欢的游戏,我觉得他们的test有问题。。。这个数量就很奇怪,不过我还是按照我的方法来,我不觉得我写错了,使用了一个bfs的算法,因为每次改变一个单词其中的一个字符,然后判断新生成的字符是否在wordList之间,然后再判断是不是已经visited过的。
1 | import java.util.*; |
Letter Combinations of a Phone Number
Letter Combinations of a Phone Number
Given a string containing digits from 2-9
inclusive, return all possible letter combinations that the number could represent.
A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.
Example:
1 | Input: "23" |
思路1:
每个数字代表几个相对应的数据,把这些代表的数据进行排列组合。这个第一个想到的就是loop,逐层递进,因为如果是三个数字的话,就是只组合成三个字母的string,可以先把1,2组合得到的结果去和3组合。这样就行了,还有别的算法。
1 | import java.util.*; |
思路2:
想学习一下dfs的算法。。。学习使用dfs和递归的方法,这个算法的思路就是直接访问到最底层的str,然后遍历最底层的list,遍历完之后返回到上一层,然后对上一层进行遍历,同时还会使用到最底层的元素。。。递归有点绕。。
1 | private List<String> letterCombinations(String digits) { |
3Sum
Given an array nums
of n integers, are there elements a, b, c in nums
such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.
Example:
1 | Given array nums = [-1, 0, 1, 2, -1, -4], |
找到三个数字和为0,这个题也是我之前就在写的一个,但是因为一些原因没做出来,然后今天下午写了一种方法,能运行,但是运行到最后一个的时候超时了,因为加了过多的sort和if的条件语句,在discussion看了一个大佬的方法之后醍醐灌顶,意识到自己少加个条件的问题。。。首先需要sort一下,然后循环遍历,在第一层循环的时候可以用sum = - num
这样就只需要在剩余的numbers里面进行一个二分查找,找到相对应的和为-num
的数据,当找到之后仍然需要接着二分查找,因为可能还有别的数字和为-num
,但是我们需要考虑的一个最重要的因素就是数字不能重复,因为同一个数字只能找到那么多和为0的list。如果大家有更好的解决方法可以给我留言。
1 | public List<List<Integer>> threeSum(int[] nums) { |
Swap Nodes in Pairs
Given a linked list, swap every two adjacent nodes and return its head.
You may not modify the values in the list’s nodes, only nodes itself may be changed.
Example:
1 | Given 1->2->3->4, you should return the list as 2->1->4->3. |
交换node的位置,两两交换,要考虑的问题有两个,list长度为odd的时候怎么办,怎么去进行loop。
1 | public ListNode swapPairs(ListNode head) { |
Generate Parentheses
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
For example, given n = 3, a solution set is:
1 | [ |
这个题主要是使用了递归的方法,首先一直添加(
,直到最深度n
,如果超过n肯定不合法了,因为左右括号是相对应的。当左括号达到最深度的时候,开始递归右括号,同时右括号的数量应该小于左括号。伪代码:
1 | def find(left, right, depth, str, res): |
Java代码:
1 | import java.util.LinkedList; |
Rotate Array
Given an array, rotate the array to the right by k steps, where k is non-negative.
Follow up:
- Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem.
- Could you do it in-place with O(1) extra space?
Example 1:
1 | Input: nums = [1,2,3,4,5,6,7], k = 3 |
Example 2:
1 | Input: nums = [-1,-100,3,99], k = 2 |
就是根据k的个数,每个element向后移动k位,超出array的话在array的开头继续。
刚开始试了好几种方法,但是都不是特别理想,看了一下discussion,学到了。这个翻转链表实际是有规律的,先把整个array reverse一下,然后再把0-k
reverse,然后把k-end
reverse一下就可以得到最终的结果。。。很神奇的规律。。。
1 | import java.util.Arrays; |
Plus One
Given a non-empty array of digits representing a non-negative integer, plus one to the integer.
The digits are stored such that the most significant digit is at the head of the list, and each element in the array contain a single digit.
You may assume the integer does not contain any leading zero, except the number 0 itself.
Example 1:
1 | Input: [1,2,3] |
Example 2:
1 | Input: [4,3,2,1] |
一个数学的问题,在最后面加1,然后如果大于10,那么前面的数字就需要加一。可以直接不用分类来讨论,我们可以设置一个循环index <= 0
,index = nums.length - 1
这样我们从最后面开始加1,overflow
是用来判断是否溢出,在循环里面如果没有溢出,就表示前面数字加一的结果不大于10,所以可以直接break。还有一种如果循环结束了依然溢出了,这时候我们需要在array里面多加一个数字在最前面。
1 | import java.util.Arrays; |
Intersection of Two Arrays II
Given two arrays, write a function to compute their intersection.
Example 1:
1 | Input: nums1 = [1,2,2,1], nums2 = [2,2] |
Example 2:
1 | Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4] |
Note:
- Each element in the result should appear as many times as it shows in both arrays.
- The result can be in any order.
这个题就稍微简单一点了,可以用HashMap来记录num1
的元素,value来存数字出现的次数。这样在遍历num2
的时候就可以直接判断了。。。刚开始想到过array的用法,但是因为key是单一的,默默被我放弃了(我就是傻逼。。。),看了一下discussion恍然大悟。。。
1 | import javax.swing.*; |
Happy Number
Write an algorithm to determine if a number n
is “happy”.
A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.
Return True if n
is a happy number, and False if not.
Example:
1 | Input: 19 |
输入一个数字,然后把数字分开,然后平方相加。比如19 = 1^2 + 9^2
得出的数字再继续进行一样的操作,一直简化到该数字到个位数,如果该数字等于1或者7的时候,就可以return true,否则的话就return false
1 | import java.util.LinkedList; |
Contains Duplicate
Given an array of integers, find if the array contains any duplicates.
Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct.
Example 1:
1 | Input: [1,2,3,1] |
Example 2:
1 | Input: [1,2,3,4] |
Example 3:
1 | Input: [1,1,1,3,3,4,3,2,4,2] |
这个题用简单的HashMap做就行,或者用hashset,我这用的是hashset。
1 | import java.util.Arrays; |
Group Anagrams
Given an array of strings, group anagrams together.
Example:
1 | Input: ["eat", "tea", "tan", "ate", "nat", "bat"], |
Note:
- All inputs will be in lowercase.
- The order of your output does not matter.
把使用同一个字符构成的string放到一起。首先确定是使用HashMap,在遍历数组的时候对每一个string先进行sort一下(或者用hash的方法,我下面有写),排过序的string当做key,如果还有相同的数据就接着添加,如果没有该key就初始化一个数组。
1 | import java.util.*; |
Search in Rotated Sorted Array
Search in Rotated Sorted Array
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,1,2,4,5,6,7]
might become [4,5,6,7,0,1,2]
).
You are given a target value to search. If found in the array return its index, otherwise return -1
.
You may assume no duplicate exists in the array.
Your algorithm’s runtime complexity must be in the order of O(log n).
Example 1:
1 | Input: nums = [4,5,6,7,0,1,2], target = 0 |
Example 2:
1 | Input: nums = [4,5,6,7,0,1,2], target = 3 |
思路,先把分割点找到,就是从哪个地方来做的rotated,比如[4,5,6,7,0,1,2]
那么分割点就是index = 3
的时候,因为是一个递增的过程,所以想找到分割点就很简单。再根据分割点做一个binary search,先分析前半段,如果能找到结果就return,如果找不到就找后半段的内容。
1 | public class SearchRotatedArray { |
344. Reverse String
Write a function that reverses a string. The input string is given as an array of characters char[]
.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
You may assume all the characters consist of printable ascii characters.
Example 1:
1 | Input: ["h","e","l","l","o"] |
Example 2:
1 | Input: ["H","a","n","n","a","h"] |
感觉没有什么技术含量,就直接reverse就行。
1 | import java.util.Arrays; |
83. Remove Duplicates from Sorted List
Given a sorted linked list, delete all duplicates such that each element appear only once.
Example 1:
1 | Input: 1->1->2 |
Example 2:
1 | Input: 1->1->2->3->3 |
在已经sorted的链表里面去除重复的值,可以使用连个指针来完成,curr来前进,temp来链接不一样的值。当temp.val != curr.val
的时候代表中间已经省略了同类项,所以直接设置temp.next = curr
然后把curr赋值给temp(temp = curr
)。
1 | public class RemoveDuplicatesfromSortedList { |
58. Length of Last Word
Given a string s consists of upper/lower-case alphabets and empty space characters ' '
, return the length of last word (last word means the last appearing word if we loop from left to right) in the string.
If the last word does not exist, return 0.
Note: A word is defined as a maximal substring consisting of non-space characters only.
Example:
1 | Input: "Hello World" |
直接split然后取最后一个,然后直接计算length
1 | public class LengthofLastWord { |
387. First Unique Character in a String
Given a string, find the first non-repeating character in it and return it’s index. If it doesn’t exist, return -1.
Examples:
1 | s = "leetcode" |
使用了HashMap的方法,当字符只出现一次就设置key为当前char,value设置为index,如果出现超过一次,就标记value是MAX。筛选HashMap里面value不是MAX,并且返回就行了。
1 | import java.util.Collections; |
61. Rotate List
Given a linked list, rotate the list to the right by k places, where k is non-negative.
Example 1:
1 | Input: 1->2->3->4->5->NULL, k = 2 |
Example 2:
1 | Input: 0->1->2->NULL, k = 4 |
做法稍微蠢了一点,我是通过先计算链表的长度,然后把k = k % length
这样就可以得到相对链表来说的第几位。然后遍历链表,当节点的index等于k的时候开始把k之后的node放到链表的起始位置。这样就完成了rotate list。
1 | public class RotateList { |
82. Remove Duplicates from Sorted List II
Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
Return the linked list sorted as well.
Example 1:
1 | Input: 1->2->3->3->4->4->5 |
Example 2:
1 | Input: 1->1->1->2->3 |
这个第83的进阶版。只要是有重复的node都需要删除掉。我们需要有一个node(last)来记录上一个访问的node,一个node(curr)来循环。如果curr.val == curr.next.val
就代表着有重复的node了,这时候找到所有重复的node,然后得到最后一个重复node的next,然后使用last链接就行,但是last需要判断是否是null,如果是null的话需要考虑到head的情况。
1 | public class RemoveDuplicatesfromSortedListII { |
48. Rotate Image
You are given an n x n 2D matrix representing an image.
Rotate the image by 90 degrees (clockwise).
Note:
You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.
Example 1:
1 | Given input matrix = |
emmm这个题我使用了另一个double array应该是不咋对
1 | import java.util.Arrays; |
92. Reverse Linked List II
Reverse a linked list from position m to n. Do it in one-pass.
Note: 1 ≤ m ≤ n ≤ length of list.
Example:
1 | Input: 1->2->3->4->5->NULL, m = 2, n = 4 |
从起始点到结束点进行reverse。首先根据curr
的index遍历到m
的时候记录一下该node start
,然后同时记录start前面的一个node pre
因为reverse结束还要把链表链接起来。当index遍历到n
的时候记录该node end
。然后使用递归进行reverse。
1 | public class ReverseLinkedListII { |
142. Linked List Cycle II
Given a linked list, return the node where the cycle begins. If there is no cycle, return null
.
To represent a cycle in the given linked list, we use an integer pos
which represents the position (0-indexed) in the linked list where tail connects to. If pos
is -1
, then there is no cycle in the linked list.
Note: Do not modify the linked list.
Example 1:
1 | Input: head = [3,2,0,-4], pos = 1 |
首先想到的就是HashMap哈哈哈哈,然后他要求说不用额外的空间,在不实用额外的空间的情况下想到了递归+循环的方法,但是时间复杂度比较高。在循环的过程中每个node都进行一个检查环的操作,并且判断在环里面是不是等于该数字,如果不等于的话就代表不是环的一个node,当出现第一个node并且是在环里面的node就代表是环的第一个节点。感觉牺牲了时间换来了空间的优化。。。。。
1 | import java.util.HashMap; |
219. Contains Duplicate II
Given an array of integers and an integer k, find out whether there are two distinct indices i and j in the array such that nums[i] = nums[j] and the absolute difference between i and j is at most k.
Example 1:
1 | Input: nums = [1,2,3,1], k = 3 |
Example 2:
1 | Input: nums = [1,0,1,1], k = 1 |
Example 3:
1 | Input: nums = [1,2,3,1,2,3], k = 2 |
本来想的是直接用for循环,根据当前数字然后向后走k位,看k位以内有没有和nums[i]
相同的数字,但是貌似bug有点多,放弃了。。改用HashMap了,key存nums[i]
,value存相对应的index。如果HashMap已经有该key则可以计算HashMap里面存的index和当前i的差值,如果小于等于K就可以直接返回了。
1 | import java.util.HashMap; |
347. Top K Frequent Elements
Given a non-empty array of integers, return the k most frequent elements.
Example 1:
1 | Input: nums = [1,1,1,2,2,3], k = 2 |
Example 2:
1 | Input: nums = [1], k = 1 |
Note:
- You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
- Your algorithm’s time complexity must be better than O(n log n), where n is the array’s size.
- It’s guaranteed that the answer is unique, in other words the set of the top k frequent elements is unique.
- You can return the answer in any order.
用HashMap可以解决,但是因为Java对HashMap有点点不太友善,我改成Python了,因为可以自定义sort 字典,这样可以根据结果排序了。。。
1 | class Solution: |
111. Minimum Depth of Binary Tree
Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
Note: A leaf is a node with no children.
Example:
Given binary tree [3,9,20,null,null,15,7]
,
1 | 3 |
return its minimum depth = 2.
关于tree的算法可以去看我另一篇文章https://shunyangli.github.io/2020/05/03/Algorithm/#more
1 | public class MinimumDepthofBinaryTree { |
112. Path Sum
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
Note: A leaf is a node with no children.
Example:
Given the below binary tree and sum = 22
,
1 | 5 |
return true, as there exist a root-to-leaf path 5->4->11->2
which sum is 22.
1 | public class PathSum { |
100. Same Tree
Given two binary trees, write a function to check if they are the same or not.
Two binary trees are considered the same if they are structurally identical and the nodes have the same value.
Example 1:
1 | Input: 1 1 |
Example 2:
1 | Input: 1 1 |
Example 3:
1 | Input: 1 1 |
思路就是左右两边的node都一样。
1 | public class SameTree { |
101. Symmetric Tree
Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
For example, this binary tree [1,2,2,3,4,4,3]
is symmetric:
1 | 1 |
But the following [1,2,2,null,3,null,3]
is not:
1 | 1 |
其实是和上面那道题一个相反的思路,上面是左右相等,这个是left = right, right = left。
1 | public class SymmetricTree { |
144. Binary Tree Preorder Traversal
Given a binary tree, return the preorder traversal of its nodes’ values.
Example:
1 | Input: [1,null,2,3] |
Follow up: Recursive solution is trivial, could you do it iteratively?
就是一个前序的遍历:根左右
1 | import java.util.LinkedList; |
162. Find Peak Element
A peak element is an element that is greater than its neighbors.
Given an input array nums
, where nums[i] ≠ nums[i+1]
, find a peak element and return its index.
The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.
You may imagine that nums[-1] = nums[n] = -∞
.
Example 1:
1 | Input: nums = [1,2,3,1] |
Example 2:
1 | Input: nums = [1,2,1,3,5,6,4] |
Follow up: Your solution should be in logarithmic complexity.
可以采用一个二分查找的方法来处理这个问题,因为已知peak number是 nums[i] > nums[i+1]
也就是说如果在array里面出现一个降序就代表着是peak number。这样的话可以使用二分查找,如果nums[mid] > nums[mid+1]
就代表该数字就是peak number,但是之前的可以还有相对应的peak number,所以就是search(nums, left, mid)
。
ps: 也有一种O(n)的方法来查找。
1 | public class FindPeakElement { |
39. Combination Sum
Given a set of candidate numbers (candidates
) (without duplicates) and a target number (target
), find all unique combinations in candidates
where the candidate numbers sums to target
.
The same repeated number may be chosen from candidates
unlimited number of times.
Note:
- All numbers (including
target
) will be positive integers. - The solution set must not contain duplicate combinations.
Example 1:
1 | Input: candidates = [2,3,6,7], target = 7, |
Example 2:
1 | Input: candidates = [2,3,5], target = 8, |
这个可以使用到回溯算法的思想,从i - nums.length
,每个都会重复,比如当i=0
的时候:
1 | 2,2,2,2 |
这样的一个规律。
1 | import java.util.*; |
46. Permutations
Given a collection of distinct integers, return all possible permutations.
Example:
1 | Input: [1,2,3] |
也是一个回溯算法,需要加一个额外的条件,不能重复,不过也是回溯算法的一个套路。伪代码:
1 | result = [] |
1 | import java.util.ArrayList; |
704. Binary Search
Given a sorted (in ascending order) integer array nums
of n
elements and a target
value, write a function to search target
in nums
. If target
exists, then return its index, otherwise return -1
.
Example 1:
1 | Input: nums = [-1,0,3,5,9,12], target = 9 |
Example 2:
1 | Input: nums = [-1,0,3,5,9,12], target = 2 |
标准的二分查找法(只能用在排过序的list里面)。有一个算法讲解:
1 | public class BinarySearch { |