LeetCode算法题
二叉树
(1)二叉树的最大深度
public int maxDepth(TreeNode root) {
return root == null ? 0 : Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
(2)二叉树的中序遍历
List<Integer> inoderList = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
if (root == null) return inoderList;
inorderTraversal(root.left);
inoderList.add(root.val);
inorderTraversal(root.right);
return inoderList;
}
(3)二叉树的前序遍历
List<Integer> preorderList = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
if(root==null) return preorderList;
preorderList.add(root.val);
preorderTraversal(root.left);
preorderTraversal(root.right);
return preorderList;
}
(3)二叉树的后序遍历
List<Integer> postList = new ArrayList<>();
public List<Integer> postorderTraversal(TreeNode root) {
if(root==null) return postList;
postorderTraversal(root.left);
postorderTraversal(root.right);
postList.add(root.val);
return postList;
}
(4)二叉树的层次遍历
二叉树的层次遍历
给定一个二叉树,返回其按层次遍历的节点值
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int level = 0;
while (!queue.isEmpty()) {
result.add(new ArrayList<>());
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode cur = queue.poll();
result.get(level).add(cur.val);
if (cur.left != null) queue.add(cur.left);
if (cur.right != null) queue.add(cur.right);
}
++level;
}
return result;
}
(5)二叉树的所有路径
public List<String> binaryTreePaths2nd(TreeNode root) {
List<String> resList = new ArrayList<>();
binaryTreePaths2ndRecur(resList, "", root);
return resList;
}
private void binaryTreePaths2ndRecur(List<String> resList, String level, TreeNode root) {
if (root != null) {
level += String.valueOf(root.val);
if (root.left == null && root.right == null) {//当前节点是叶子节点
resList.add(level);
} else {//当前节点是非叶子节点
level += "->";
binaryTreePaths2ndRecur(resList, level, root.left);
binaryTreePaths2ndRecur(resList, level, root.right);
}
}
}
(6)对称二叉树
对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
public boolean isMirror(TreeNode t1, TreeNode t2) {
if (t1 == null && t2 == null) return true;
if (t1 == null || t2 == null) return false;
return (t1.val == t2.val)
&& isMirror(t1.right, t2.left)
&& isMirror(t1.left, t2.right);
}
回文数
(1)回文数
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
class Solution {
public boolean isPalindrome(int x) {
if(x<0)
return false;
int rem=0,y=0;
int quo=x;
while(quo!=0){
rem=quo%10;
y=y*10+rem;
quo=quo/10;
}
return y==x;
}
}
(2)回文子串
回文子串
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。
class Solution {
int num = 0;
public int countSubstrings(String s) {
for (int i=0; i < s.length(); i++){
count(s, i, i);//回文串长度为奇数
count(s, i, i+1);//回文串长度为偶数
}
return num;
}
public void count(String s, int start, int end){
while(start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)){
num++;
start--;
end++;
}
}
}
(3)最长回文子串
最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return "";
}
// 保存起始位置,测试了用数组似乎能比全局变量稍快一点
int[] range = new int[2];
char[] str = s.toCharArray();
for (int i = 0; i < s.length(); i++) {
// 把回文看成中间的部分全是同一字符,左右部分相对称
// 找到下一个与当前字符不同的字符
i = findLongest(str, i, range);
}
return s.substring(range[0], range[1] + 1);
}
public static int findLongest(char[] str, int low, int[] range) {
// 查找中间部分
int high = low;
while (high < str.length - 1 && str[high + 1] == str[low]) {
high++;
}
// 定位中间部分的最后一个字符
int ans = high;
// 从中间向左右扩散
while (low > 0 && high < str.length - 1 && str[low - 1] == str[high + 1]) {
low--;
high++;
}
// 记录最大长度
if (high - low > range[1] - range[0]) {
range[0] = low;
range[1] = high;
}
return ans;
}
}
哈希表
(1)两数之和
两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] indexs = new int[2];
// 建立k-v ,一一对应的哈希表
HashMap<Integer,Integer> hash = new HashMap<Integer,Integer>();
for(int i = 0; i < nums.length; i++){
if(hash.containsKey(nums[i])){
indexs[0] = i;
indexs[1] = hash.get(nums[i]);
}
// 将数据存入 key为补数 ,value为下标
hash.put(target-nums[i],i);
}
return indexs;
}
}
(2)无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
Map<Character, Integer> map = new HashMap<>(); // current index of character
// try to extend the range [i, j]
for (int j = 0, i = 0; j < n; j++) {
if (map.containsKey(s.charAt(j))) {
i = Math.max(map.get(s.charAt(j)), i);
}
ans = Math.max(ans, j - i + 1);
map.put(s.charAt(j), j + 1);
}
return ans;
}
}
链表
(1)两数相加
两数相加
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode head = new ListNode(0);
ListNode rs = head;
int carry = 0;
while( l1 != null || l2 != null || carry != 0){
int num1 = l1 != null ? l1.val : 0;
int num2 = l2 != null ? l2.val : 0;
int sum = num1 + num2 +carry;
carry = sum/10;
ListNode sumNode = new ListNode(sum%10);
rs.next = sumNode;
rs = sumNode;
if(l1!=null) l1 = l1.next;
if(l2!=null) l2 = l2.next;
}
return head.next;
}
}
(2)删除链表的倒数第N个节点
删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode temp = head;
Map<Integer,ListNode> m = new HashMap<Integer,ListNode>();
int index=1;
while(temp!=null){
m.put(index++,temp);
temp = temp.next;
}
int size = m.size();
if(size == 1)
return null;
if(n == 1){
m.get(size-1).next = null;
}else if(n == size){
head = head.next;
}else{
m.get(size-n).next = m.get(size-n+2);
}
return head;
}
}
(3)合并两个有序链表
合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) {
return l2;
}
else if (l2 == null) {
return l1;
}
else if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
}
else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
(4)环形链表
给定一个链表,判断链表中是否有环。
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode slow = head;
ListNode fast = head.next;
while (slow != fast) {
if (fast == null || fast.next == null) {
return false;
}
slow = slow.next;
fast = fast.next.next;
}
return true;
}
}
(5)合并K个排序链表
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0) return null;
return solve(lists, 0, lists.length-1);
}
private ListNode solve(ListNode[] arr, int left, int right){
if(left == right) return arr[left];
int mid = (left + right) >> 1;
ListNode lNode = solve(arr, left, mid);
ListNode rNode = solve(arr, mid+1, right);
return merge(lNode, rNode);
}
private ListNode merge(ListNode node1, ListNode node2){
if(node1 == null) return node2;
if(node2 == null) return node1;
if(node1.val < node2.val){
node1.next = merge(node1.next, node2);
return node1;
}else{
node2.next = merge(node1, node2.next);
return node2;
}
}
}
(6)删除排序链表中的重复元素
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode current = head;
while (current != null && current.next != null) {
if (current.next.val == current.val) {
current.next = current.next.next;
} else {
current = current.next;
}
}
return head;
}
}
二分查找
(1)寻找两个有序数组的中位数
寻找两个有序数组的中位数
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
class Solution {
public double findMedianSortedArrays(int[] A, int[] B) {
int m = A.length;
int n = B.length;
if (m > n) { // to ensure m<=n
int[] temp = A; A = B; B = temp;
int tmp = m; m = n; n = tmp;
}
int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
while (iMin <= iMax) {
int i = (iMin + iMax) / 2;
int j = halfLen - i;
if (i < iMax && B[j-1] > A[i]){
iMin = i + 1; // i is too small
}
else if (i > iMin && A[i-1] > B[j]) {
iMax = i - 1; // i is too big
}
else { // i is perfect
int maxLeft = 0;
if (i == 0) { maxLeft = B[j-1]; }
else if (j == 0) { maxLeft = A[i-1]; }
else { maxLeft = Math.max(A[i-1], B[j-1]); }
if ( (m + n) % 2 == 1 ) { return maxLeft; }
int minRight = 0;
if (i == m) { minRight = B[j]; }
else if (j == n) { minRight = A[i]; }
else { minRight = Math.min(B[j], A[i]); }
return (maxLeft + minRight) / 2.0;
}
}
return 0.0;
}
}
(2)二分查找
二分查找
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1; // 注意
while(left <= right) {
int mid = (right + left) / 2;
if(nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1; // 注意
else if (nums[mid] > target)
right = mid - 1; // 注意
}
return -1;
}
}
(3)反转字符串
class Solution {
public void reverseString(char[] s) {
if(s.length<2){
return;
}
int left = -1;
int right = s.length;
while(++left<--right){
char temp = s[left];
s[left] = s[right];
s[right] = temp;
}
}
}
回溯法
(1)N皇后
class Solution {
int rows[];
// "hill" diagonals
int hills[];
// "dale" diagonals
int dales[];
int n;
// output
List<List<String>> output = new ArrayList();
// queens positions
int queens[];
public boolean isNotUnderAttack(int row, int col) {
int res = rows[col] + hills[row - col + 2 * n] + dales[row + col];
return (res == 0) ? true : false;
}
public void placeQueen(int row, int col) {
queens[row] = col;
rows[col] = 1;
hills[row - col + 2 * n] = 1; // "hill" diagonals
dales[row + col] = 1; //"dale" diagonals
}
public void removeQueen(int row, int col) {
queens[row] = 0;
rows[col] = 0;
hills[row - col + 2 * n] = 0;
dales[row + col] = 0;
}
public void addSolution() {
List<String> solution = new ArrayList<String>();
for (int i = 0; i < n; ++i) {
int col = queens[i];
StringBuilder sb = new StringBuilder();
for(int j = 0; j < col; ++j) sb.append(".");
sb.append("Q");
for(int j = 0; j < n - col - 1; ++j) sb.append(".");
solution.add(sb.toString());
}
output.add(solution);
}
public void backtrack(int row) {
for (int col = 0; col < n; col++) {
if (isNotUnderAttack(row, col)) {
placeQueen(row, col);
// if n queens are already placed
if (row + 1 == n) addSolution();
// if not proceed to place the rest
else backtrack(row + 1);
// backtrack
removeQueen(row, col);
}
}
}
public List<List<String>> solveNQueens(int n) {
this.n = n;
rows = new int[n];
hills = new int[4 * n - 1];
dales = new int[2 * n - 1];
queens = new int[n];
backtrack(0);
return output;
}
}
动态规划
(1)最大子序和
最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
class Solution {
public int maxSubArray(int[] nums) {
int result = nums[0];
int sum = 0;
for (int num : nums){
if(sum<=0){
sum = num;
}else{
sum = num + sum;
}
result = Math.max(sum,result);
}
return result;
}
}
其他
(1)整数反转
整数反转
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
class Solution {
public int reverse(int x) {
long temp=0;
while(x!=0){
temp*=10;
temp+=x%10;
x/=10;
}
if(temp<Integer.MIN_VALUE || temp>Integer.MAX_VALUE)
return 0;
return (int)temp;
}
}
(2)盛最多水的容器
盛最多水的容器
给定 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
class Solution {
public int maxArea(int[] height) {
int max=0;
int i=0,j=height.length-1;
while(i<j){
int temp = (j-i)*(height[i]>height[j]? height[j--]:height[i++]);
if (temp > max) max=temp;
}
return max;
}
}
(3)整数转罗马数字
class Solution {
public String intToRoman(int num) {
int values[]=new int[]{1000,900,500,400,100,90,50,40,10,9,5,4,1};
String strs[]=new String[]{"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
String str="";
for(int i=0; i<13; i++){
if(num==0)
break;
int times=num/values[i];
if(times==0)
continue;
for(int t=0;t<times;t++)
{
str+=strs[i];
}
num=num-(times*values[i]);
}
return str;
}
}
(4)罗马数字转整数
class Solution {
public int romanToInt(String s) {
String[] roman = { "IV", "IX", "XL", "XC", "CD", "CM", "I", "V", "X", "L", "C", "D", "M" };
int[] nums = { 4, 9, 40, 90, 400, 900, 1, 5, 10, 50, 100, 500, 1000 };
int num = 0;
while (s.length() > 0) {
for (int i = 0; i < roman.length; i++) {
if (s.startsWith(roman[i])) {
num += nums[i];
s = s.substring(roman[i].length());
break;
}
}
}
return num;
}
}
(5)最长公共前缀
最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例 1:
输入: [“flower”,“flow”,“flight”]
输出: “fl”
class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs.length == 0)
return "";
String ans = strs[0];
for(int i =1;i<strs.length;i++) {
int j=0;
for(;j<ans.length() && j < strs[i].length();j++) {
if(ans.charAt(j) != strs[i].charAt(j))
break;
}
ans = ans.substring(0, j);
if(ans.equals(""))
return ans;
}
return ans;
}
}
(6)三数求和
三数求和
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ls = new ArrayList<>();
for (int i = 0; i < nums.length - 2; i++) {
if (i == 0 || (i > 0 && nums[i] != nums[i - 1])) { // 跳过可能重复的答案
int l = i + 1, r = nums.length - 1, sum = 0 - nums[i];
while (l < r) {
if (nums[l] + nums[r] == sum) {
ls.add(Arrays.asList(nums[i], nums[l], nums[r]));
while (l < r && nums[l] == nums[l + 1]) l++;
while (l < r && nums[r] == nums[r - 1]) r--;
l++;
r--;
} else if (nums[l] + nums[r] < sum) {
while (l < r && nums[l] == nums[l + 1]) l++; // 跳过重复值
l++;
} else {
while (l < r && nums[r] == nums[r - 1]) r--;
r--;
}
}
}
}
return ls;
}
}
(7)x 的平方根
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
class Solution {
public int mySqrt(int x) {
// 注意:针对特殊测试用例,例如 2147395599
// 要把搜索的范围设置成长整型
// 为了照顾到 0 把左边界设置为 0
long left = 0;
// # 为了照顾到 1 把右边界设置为 x // 2 + 1
long right = x / 2 + 1;
while (left < right) {
// 注意:这里一定取右中位数,如果取左中位数,代码会进入死循环
long mid = left + (right - left + 1) / 2;
// long mid = (left + right + 1) >>> 1;
long square = mid * mid;
if (square > x) {
right = mid - 1;
} else {
left = mid;
}
}
// 因为一定存在,因此无需后处理
return (int) left;
}
}