class Solution {
public ListNode reverseList(ListNode head) {
if(head==null) return null;
ListNode cur = head;
ListNode pre = null;
while (cur!=null){
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
}
class Solution {
public int findKthLargest(int[] nums, int k) {
if(nums.length==0 || nums==null) return 0;
PriorityQueue<Integer> queue = new PriorityQueue<>();
for(int i=0;i<nums.length;i++){
if(queue.size()<k){
queue.offer(nums[i]);
}else if(nums[i]>queue.peek()){
queue.poll();
queue.offer(nums[i]);
}
}
return queue.peek();
}
}
快速排序:
1、选取基准数(这里以序列的第一个元素为基准数)。分配 左、右指针(左指针一开始指向序列的最左端,即 left = 0,右指针一开始指向序列的最右端,即 right = nums.Length - 1)
2、右指针先往左走,当右指针指向元素比基准数小时,将该元素放到左指针指向的位置(这么做是为了把该数放到基准数的左边)
3、右指针把元素放到左指针位置后,左指针开始向右走。当左指针指向元素比基准数大时,把该元素放到右指针的位置。
4、填了右边的空缺后,右指针继续向左移动,开始填左边的空缺,填了左边 接着填右边,填了右边 接着填左边,直到 左指针 与 右指针相遇,此时 两个指针共同指向的位置是一个 “空缺”,我们把基准数 “填” 到该 “空缺” 中,这样 基准数 左边的元素都小于基准数,基准数右边的元素都大于基准数,基准数排序到了争取的位置。
5、基准数把序列分成了 左序列 和 右序列,递归地对 左序列 和 右序列 执行上面的步骤。这样,每排序出一个基准数,就会把序列分的更细。
终止条件:当前被分离的序列长度只有 1 时,就无需再排序了。
//快排就是给基准元素找位置的过程
private static void quickSort(int[] arr, int low, int high) {
//递归的终止条件
if(low>high) return;
//找出基准元素的位置
int index = getIndex(arr,low,high);
//进行迭代对index之前和之后的数组进行相同的操作使整个数组变成有序
quickSort(arr,low,index-1);
quickSort(arr,index+1,high);
}
//目标是将比基准元素大的数据放到基准元素的右边,把比基准元素小的数据放到基准元素的左边
//当两个指针重合时就是基准元素的位置
private static int getIndex(int[] arr, int low, int high) {
//利用一个临时变量,将基准数据保存下来
int tmp = arr[low];
while (low<high){
//先从后到前进行扫描,如果尾部的元素大于等于基准数据tmp,就将high--
while (low<high && arr[high]>=tmp){
high--;
}
//否则如果尾部元素小于tmp了,需要将其赋值给low
arr[low] = arr[high];
//再从后向前进行扫描,如果头部的元素小于等于基准数据tmp,就将low++
while (low<high && arr[low]<=tmp){
low++;
}
//否则如果头部元素大于tmp了,需要将其赋值给low
arr[high] = arr[low];
}
//退出循环后,说明此时high==low,让基准数组赋值给当前值
arr[low] = tmp;
//返回基准位置,此事比基准数据大的都在基准数据的右边,比它小的都在左边
return low;
}
//定义一个指针维持一个滑动窗口,start指向子串的第一个位置,end指向子串的最后一个位置
//每次通过end将窗口向右滑动,如果遇到和窗口内元素重复的元素就让start向前移动
public class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.length()==0 || s==null) return 0;
int res = 0;
//子串的开始位置
int start = 0;
HashMap<Character,Integer> map = new HashMap<>();
for(int end=0;end<s.length();end++){
if(map.containsKey(s.charAt(end))){
//如果没有取最大值会报错,不如abba,本来结果应该为2,却输出3
start= Math.max(start,map.get(s.charAt(end))+1);
}
map.put(s.charAt(end),end);
res = Math.max(res,end-start+1);
}
return res;
}
}
public class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode p1 = dummy;
ListNode p2 = head;
for(int i=0;i<m-1;i++){
p1 = p1.next;
p2 = p2.next;
}
ListNode cur = null;
for(int i=0;i<n-m;i++){
cur = p2.next;
p2.next = p2.next.next;
cur.next = p1.next;
p1.next = cur;
}
return dummy.next;
}
}
public class Solution {
public int singleNumber(int[] nums) {
//a^0 = a; a^a = 0;
int res = 0;
for(int i=0;i<nums.length;i++){
res = res ^ nums[i];
}
return res;
}
}
public class Solution {
public boolean isValid(String s) {
if(s.length()==0 || s==null) return true;
Stack<Character> stack = new Stack<>();
char[] charArray = s.toCharArray();
for (int i=0;i<charArray.length;i++){
if(charArray[i]=='('){
stack.push(')');
}else if(charArray[i]=='['){
stack.push(']');
}else if(charArray[i]=='{'){
stack.push('}');
}else {
//说明只剩余一个}
if(stack.isEmpty()){
return false;
}
if(stack.pop()!=charArray[i]){
return false;
}
}
}
return stack.isEmpty();
}
}
public class Solution {
public String reverseWords(String s) {
if(s==null || s.length()==0) return null;
//正则表达式中\s匹配任何空白字符,包括空格、制表符、换页符等等
//而“\s+”则表示匹配任意多个上面的字符。另因为反斜杠在Java里是转义字符,所以在Java里,我们要这么用“\\s+”.
String[] str = s.trim().split("//s+");
StringBuilder sb = new StringBuilder();
for(int i=str.length-1;i>=0;i--){
sb.append(str[i]+" ");
}
return sb.toString().trim();
}
}
方法二:
public class Solution {
public String reverseWords(String s) {
if(s==null || s.length()==0) return "";
//正则表达式中\s匹配任何空白字符,包括空格、制表符、换页符等等
//而“\s+”则表示匹配任意多个上面的字符。另因为反斜杠在Java里是转义字符,所以在Java里,我们要这么用“\\s+”.
String[] str = s.trim().split(" ");
StringBuilder sb = new StringBuilder();
for(int i=str.length-1;i>=0;i--){
if(str[i].equals("")) continue;
sb.append(str[i]+" ");
}
return sb.toString().trim();
}
}
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if(root==null) return res;
LinkedList<TreeNode> queue = new LinkedList<>();
queue.add(root);
int level = 1;
while (!queue.isEmpty()){
int len = queue.size();
ArrayList<Integer> list = new ArrayList<>();
for(int i=0;i<len;i++){
TreeNode node = queue.pop();
if(level%2==1){
list.add(node.val);
}else{
list.add(0,node.val);
}
if(node.left!=null){
queue.add(node.left);
}
if(node.right!=null){
queue.add(node.right);
}
}
res.add(list);
level++;
}
return res;
}
}
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//不需要重新定义cur1和cur2指向l1和l2
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
while (l1!=null && l2!=null){
if(l1.val<l2.val){
cur.next = l1;
l1 = l1.next;
}else{
cur.next = l2;
l2 = l2.next;
}
cur = cur.next;
}
//注意是l1!=null 而不是l1.next!=null
if(l1 !=null){
cur.next = l1;
}else{
cur.next = l2;
}
return dummy.next;
}
}
class Solution {
//初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m-1;
int j = n-1;
int k = m+n-1;
while (i>=0 && j>=0){
nums1[k--] = nums1[i]>nums2[j] ? nums1[i--] : nums2[j--];
}
while (j>=0){
nums1[k--] = nums2[j--];
}
}
}
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[] twoSum(int[] nums, int target) {
if(nums.length==0 || nums==null) return new int[0];
HashMap<Integer,Integer> map = new HashMap<>();
for(int i=0;i<nums.length;i++){
if(map.containsKey(target-nums[i])){
return new int[]{map.get(target-nums[i]),i};
}
map.put(nums[i],i);
}
return null;
}
}
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<nums.length;i++){
//去重
if(i>0 && nums[i]==nums[i-1]) continue;
int left = i+1;
int right = nums.length-1;
while (left<right){
int sum = nums[left]+nums[right]+nums[i];
if(sum==0){
res.add(Arrays.asList(nums[i],nums[left],nums[right]));
//去重
while (left<right && nums[left]==nums[left+1]) left++;
while (left<right && nums[right]==nums[right-1]) right--;
//这个地方别忘了
left++;
right--;
} else if(sum>0){
right--;
}else{
left++;
}
}
}
return res;
}
}
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
//注意,res初始化不能够为0
int res = nums[0]+nums[1]+nums[2];
for(int i=0;i<nums.length;i++){
int left = i+1;
int right = nums.length-1;
while (left<right){
int sum = nums[left]+nums[right]+nums[i];
if(sum>target){
right--;
}else{
left++;
}
if(Math.abs(sum-target)<Math.abs(res-target)){
res = sum;
}
}
}
return res;
}
}
class Solution {
public int[] searchRange(int[] nums, int target) {
//二分查找
if(nums.length==0 || nums==null) return new int[]{-1,-1};
int first = findFirst(nums, target);
if(first==-1) return new int[]{-1,-1};
int end = finEnd(nums, target);
return new int[]{first,end};
}
private int findFirst(int[] nums, int target) {
int start = 0;
int end = nums.length-1;
while (start+1<end){
int mid = start + (end-start)/2;
if(nums[mid]<target){
start = mid;
}else{
end = mid;
}
}
if(nums[start]==target) return start;
if(nums[end]==target) return end;
return -1;
}
private int finEnd(int[] nums, int target) {
int start = 0;
int end = nums.length-1;
while (start+1<end){
int mid = start+(end-start)/2;
if(nums[mid]<=target){
start = mid;
}else{
end = mid;
}
}
if(nums[end]==target) return end;
if(nums[start]==target) return start;
return -1;
}
}
class CQueue {
Stack stack1;
Stack stack2;
public CQueue() {
stack1 = new Stack<>();
stack2 = new Stack<>();
}
public void appendTail(int value) {
stack1.push(value);
}
public int deleteHead() {
if(!stack2.isEmpty()) return stack2.pop();
if(stack1.isEmpty()) return -1;
while (!stack1.isEmpty()){
stack2.push(stack1.pop());
}
return stack2.pop();
}
}
递归方法:
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
dfs(root);
return res;
}
private void dfs(TreeNode root) {
if(root==null) return;
res.add(root.val);
dfs(root.left);
dfs(root.right);
}
}
迭代方法:
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
if(root==null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
if(node!=null){
if(node.right!=null) stack.push(node.right);
if(node.left!=null) stack.push(node.left);
stack.push(node);
stack.push(null);
}else {
res.add(stack.pop().val);
}
}
return res;
}
}
class Solution {
public int maxProduct(int[] nums) {
//寻找数组中两个最大值和其下标
//第一个最大值
int max = 0;
int maxIndex = 0;
for(int i=0;i<nums.length;i++){
if(nums[i]>max){
max = nums[i];
maxIndex = i;
}
}
int secnodMax = 0;
int secondIndex = 0;
//第二个最大值
for(int i=0;i<nums.length;i++){
if(secnodMax<nums[i] && nums[i]<=max &&i!=maxIndex){
secnodMax = nums[i];
secondIndex = i;
}
}
return (max-1)*(secnodMax-1);
}
}
class Solution {
public int search(int[] nums, int target) {
if(nums==null || nums.length==0) return 0;
int start = 0;
int end = nums.length-1;
while (start+1<end){
int mid = start+(end-start)/2;
//如果前半段是递增的序列
if(nums[start]<=nums[mid]){
if(nums[start]<=target && target<=nums[mid]){
end = mid;
}else {
start = mid;
}
//如果后半段是递增序列
}else{
if(nums[mid]<=target && target<=nums[end]){
start = mid;
}else{
end = mid;
}
}
}
if(nums[start]==target) return start;
if(nums[end]==target) return end;
return -1;
}
}
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null) return null;
ListNode slow = head;
ListNode fast = head;
while (true){
//如果不成环,直接返回null
if(fast==null || fast.next==null) return null;
fast = fast.next.next;
slow = slow.next;
if(fast==slow) break;
}
slow = head;
while (slow!=fast){
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
class Solution {
public int maxSubArray(int[] nums) {
if(nums.length==0 || nums==null) return 0;
int n = nums.length;
int[] dp = new int[n];
dp[0] = nums[0];
int res = dp[0];
for(int i=1;i<n;i++){
dp[i] = Math.max(dp[i-1]+nums[i],nums[i]);
//需要使用res记录之前的和现在加上num[i]后哪个更大:-1 1 -3 4 -1 2 1 -5 4
res = Math.max(res,dp[i]);
}
return res;
}
}
class Solution {
public int coinChange(int[] coins, int amount) {
if(coins.length==0 || coins==null) return 0;
int[] dp = new int[amount+1];
dp[0] = 0;
for(int i=1;i<=amount;i++){
dp[i] = amount+1;
for(int j = 0;j<coins.length;j++){
if(i>=coins[j]){
dp[i] = Math.min(dp[i-coins[j]]+1,dp[i]);
}
}
}
return dp[amount] == amount+1?-1:dp[amount];
}
}
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if(head==null) return null;
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode cur = dummy;
while (cur.next!=null){
if(cur.next.val==val) {
cur.next = cur.next.next;
//假如删除的是最后一个节点,但是又没加break,会保存空指针异常
break;
}
cur = cur.next;
}
return dummy.next;
}
}
class Solution {
public ListNode deleteNode(ListNode head, int val) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode cur = dummy;
//找到要删除节点的前一个节点
while (cur.next.val!=val){
cur = cur.next;
}
//然后让他指向下一个节点
cur.next = cur.next.next;
return dummy.next;
}
}
class Solution {
public int fib(int N) {
if(N==0) return 0;
if(N==1) return 1;
int[] dp = new int[N+1];
dp[0] = 0;
dp[1] = 1;
for(int i=2;i<=N;i++){
dp[i] = dp[i-1]+dp[i-2];
}
return dp[N];
}
}
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
if(head==null) return null;
ListNode fast = head;
ListNode slow = head;
for(int i=0;i<k;i++){
fast = fast.next;
}
while (fast!=null){
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
BFS:time (n) space:O(n)
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root==null) return res;
LinkedList<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()){
int len = queue.size();
for(int i=0;i<len;i++){
TreeNode node = queue.poll();
if(node.left!=null) queue.add(node.left);
if(node.right!=null) queue.add(node.right);
//将这一层节点从左到右加入队列,将这一层的最后一个节点放入res
if(i==len-1) res.add(node.val);
}
}
return res;
}
}
DFS:time (n) space:O(n)
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> rightSideView(TreeNode root) {
if(root==null) return res;
int level = 0;
dfs(root,level);
return res;
}
private void dfs(TreeNode root, int level) {
if(root==null) return;
//前序遍历的变形
//说明这一层还没有元素装进来
if(level==res.size()){
res.add(root.val);
}
level++;
//先遍历右子树,因为是右视图
dfs(root.right,level);
dfs(root.left,level);
}
}
class Solution {
public int mySqrt(int x) {
//需要定义为long,防止内存溢出
int start = 1;
int end = x;
//二分查找算法
while (start+1<end){
int mid = start+(end-start)/2;
if(mid*mid<x){
start = mid;
}else{
end = mid;
}
}
if(end*end==x) return end;
return start;
}
}
不保证稳定性使用双指针:
class Solution {
public int[] exchange(int[] nums) {
if(nums.length==0 || nums==null) return nums;
int left = 0;
int right = nums.length-1;
while (left<right){
while (left<right && nums[left]%2==1) left++;
while (left<right && nums[right]%2==0) right--;
int tmp = nums[left];
nums[left] = nums[right];
nums[right] = tmp;
}
return nums;
}
}
保证稳定性使用插入排序算法:
public class Solution {
public void reOrderArray(int [] array) {
if(array.length==0 || array==null) return;
for(int i=1;i<array.length;i++){
int insertValue= array[i];
if(array[i] % 2 == 1){
int insertIndex = i;
//注意是array[insertIndex-1] 而不是array[i-1]
while (insertIndex>=1 && array[insertIndex-1]%2==0){
array[insertIndex] = array[insertIndex-1];
insertIndex--;
}
array[insertIndex] = insertValue;
}
}
}
}
反转数组的方法: 如果 k 大于n,移动 k 次实际上相当于移动 k%n 次。
这个方法基于这个事实:当我们旋转数组 k 次, k%n 个尾部元素会被移动到头部,剩下的元素会被向后移动。
在这个方法中,我们首先将所有元素反转。然后反转前 k 个元素,再反转后面 n-k 个元素,就能得到想要的结果。
原始数组 : 1 2 3 4 5 6 7
反转所有数字后 : 7 6 5 4 3 2 1
反转前 k 个数字后 : 5 6 7 4 3 2 1
反转后 n-k 个数字后 : 5 6 7 1 2 3 4 --> 结果
class Solution {
public void rotate(int[] nums, int k) {
k = k%(nums.length);
reverse(nums,0,nums.length-1);
reverse(nums,0,k-1);
reverse(nums,k,nums.length-1);
}
private void reverse(int[] nums, int left, int right) {
while (left<right){
int tmp = nums[left];
nums[left] = nums[right];
nums[right] = tmp;
left++;
right--;
}
}
}
暴力算法:
class Solution {
public void rotate(int[] nums, int k) {
int n = nums.length;
k = k%n;
//思想就像插入排序
for(int i=0;i<k;i++){
//将最后一个数暂存下来
int tmp = nums[n-1];
//将前面的数都向后移动一位
for(int j=n-1;j>0;j--){
nums[j] = nums[j-1];
}
//将暂存的数插入到首位
nums[0] = tmp;
}
}
}
摩尔投票法:
class Solution {
//众数出现的次数超过数组长度的一半;
//若记众数的票数为+1,非众数的票数为-1,则一定有所有数字的票数和 > 0 。
public int majorityElement(int[] nums) {
if(nums.length==0 || nums==null) return 0;
int mainNum = 0;
int count = 0;
for(int i=0;i<nums.length;i++){
//如果票数减为0,更换众数
if(count==0) {
mainNum = nums[i];
}
//遇到众数+1
if(nums[i]==mainNum) count++;
//遇到非众数-1
else count--;
}
return mainNum;
}
}
快速排序:
class Solution {
//众数一定是排序数组的中间的数
public int majorityElement(int[] nums) {
int left = 0;
int right = nums.length-1;
quickSort(nums,left,right);
return nums[right/2];
}
private void quickSort(int[] nums, int left, int right) {
if(left>right) return;
int index = getIndex(nums,left,right);
quickSort(nums,left,index-1);
quickSort(nums,index+1,right);
}
private int getIndex(int[] nums, int left, int right) {
int tmp = nums[left];
while (left<right){
while (left<right && nums[right]>=tmp) right--;
nums[left] = nums[right];
while (left<right && nums[left]<=tmp) left++;
nums[right] = nums[left];
}
nums[left] = tmp;
return left;
}
}
class Solution {
public int singleNonDuplicate(int[] nums) {
//a^a=0 a^0=a
int res = 0;
for(int i=0;i<nums.length;i++){
res = res^nums[i];
}
return res;
}
}
递归方法:
class Solution {
List res = new ArrayList<>();
public List inorderTraversal(TreeNode root) {
if(root==null) return res;
dfs(root);
return res;
}
private void dfs(TreeNode root) {
if(root==null) return;
dfs(root.left);
res.add(root.val);
dfs(root.right);
}
}
迭代方法:
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
if(root==null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
if(node!=null){
if(node.right!=null) stack.push(node.right);
stack.push(node);
stack.push(null);
if(node.left!=null) stack.push(node.left);
}else{
res.add(stack.pop().val);
}
}
return res;
}
}
class Solution {
public int countDigitOne(int n) {
return f(n);
}
private int f(int n) {
if(n<=0) return 0;
String s = String.valueOf(n);
//计算n的最高位
int high = s.charAt(0)-'0';
int pow = (int) Math.pow(10,s.length()-1);
//计算n的低位
int last = n-high*pow;
if(high==1){
return f(pow-1)+ last+1 +f(last);
}else{
return f(pow-1)*high + pow + f(last);
}
}
}
class Solution {
Node head;
Node pre;
public Node treeToDoublyList(Node root) {
if(root==null) return null;
dfs(root);
pre.right = head;
head.left = pre;
return head;
}
private void dfs(Node cur) {
if(cur==null) return;
dfs(cur.left);
if(pre==null) head = cur;
else pre.right = cur;
cur.left = pre;
pre = cur;
dfs(cur.right);
}
}
//输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
//输出:7 -> 0 -> 8
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
int sum = 0;
while (l1!=null || l2!=null){
if(l1!=null){
sum = sum + l1.val;
l1 = l1.next;
}
if(l2!=null){
sum = sum +l2.val;
l2 = l2.next;
}
cur.next = new ListNode(sum%10);
sum = sum/10;
cur = cur.next;
}
if(sum==1){
cur.next = new ListNode(1);
}
return dummy.next;
}
}
class Solution {
//两数相加的思想
public String addStrings(String num1, String num2) {
//用两个指针从尾部遍历两个字符串,逐位相加
int i = num1.length()-1;
int j = num2.length()-1;
//进位
int carry = 0;
StringBuilder sb = new StringBuilder();
while (i>=0 || j>=0){
//两个数可能位数不同 51189 917895 ,位数小的前面添加0
int n1 = i>=0 ? num1.charAt(i)-'0' : 0;
int n2 = j>=0 ? num2.charAt(j)-'0' : 0;
int sum = n1+n2+carry;
carry = sum/10;
sb.append(sum%10);
i--;
j--;
}
if(carry==1) sb.append(1);
return sb.reverse().toString();
}
}
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(0);
ListNode l1 = dummy;
dummy.next = head;
ListNode l2 = head;
while (l2!=null && l2.next !=null){
//最好用两个变量存一下,不然变量指针移动后就乱了
ListNode start = l2.next;
ListNode nextStart = l2.next.next;
l1.next = start;
start.next = l2;
l2.next = nextStart;
l1 = l2;
l2 = l2.next;
}
return dummy.next;
}
}
class Solution {
public int[] twoSum(int[] nums, int target) {
if(nums.length==0 || nums==null) return null;
HashMap<Integer,Integer> map = new HashMap<>();
for(int i=0;i<nums.length;i++){
if(map.containsKey(target-nums[i])){
return new int[]{map.get(target-nums[i]),i};
}
map.put(nums[i],i);
}
return null;
}
}
timeSpace:O(n∗log(k)),n
是所有链表中元素的总和,k
是链表个数。
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists==null || lists.length==0) return null;
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
PriorityQueue<ListNode> queue = new PriorityQueue<>(new Comparator<ListNode>(){
@Override
public int compare(ListNode o1, ListNode o2) {
return o1.val-o2.val;
}
});
for(int i=0;i<lists.length;i++){
if(lists[i]!=null){
queue.offer(lists[i]);
}
}
while (!queue.isEmpty()){
//弹出头节点最小的链表
cur.next = queue.poll();
cur = cur.next;
if(cur.next!=null){
queue.offer(cur.next);
}
}
return dummy.next;
}
}
class Solution {
public int singleNumber(int[] nums) {
HashMap<Integer,Integer> map = new HashMap<>();
for(int i=0;i<nums.length;i++){
if(map.containsKey(nums[i])){
map.put(nums[i],map.get(nums[i])+1);
}else{
map.put(nums[i],1);
}
}
Set<Integer> set = map.keySet();
for(Integer key:set){
if(map.get(key)==1) {
return key;
}
}
return -1;
}
}
class Solution {
public ListNode deleteDuplicates(ListNode head) {
//必须判断这个条件
if(head==null || head.next==null) return head;
ListNode cur = head;
while (cur.next != null){
if(cur.val==cur.next.val){
cur.next = cur.next.next;
//必须使用else,否则删除不了所有的重复元素,比如111111
}else{
cur = cur.next;
}
}
return head;
}
}
暴力解法:
class Solution {
public static int countPrimes(int n) {
int count = 0;
for (int i = 2; i < n; i++){
if (isPrime(i)) count++;
}
return count;
}
//判断整数n是否是素数,如果n能够整除其他数就不是素数
public static boolean isPrime(int n) {
for (int i = 2; i < n; i++)
if (n % i == 0){
return false;
}
return true;
}
}
厄拉多塞筛法:
class Solution {
public int countPrimes(int n) {
//定义一个Boolean类型变量,代表这个数是否为素数,初始化是false,代表是素数
boolean[] isnotPrimes = new boolean[n];
int count = 0;
for(int i=2;i<n;i++){
//如果当前数是质数,将质数的倍数删除,一定不是质数
if(isnotPrimes[i]==false){
//是质数,数量加1
count++;
for(int j=2; i*j<n;j++){
isnotPrimes[i*j] = true;
}
}
}
return count;
}
}
class Solution {
List<String> res = new ArrayList<>();
public List<String> generateParenthesis(int n) {
if(n==0) return res;
String s = "";
dfs(s,n,n);
return res;
}
/**
* @param s 路径
* @param remainingLeft 剩下的左括号个数
* @param remainingRight 剩下的右括号个数
*/
private void dfs(String s, int remainingLeft , int remainingRight) {
//添加路径
if(remainingLeft==0 && remainingRight==0){
res.add(s);
return;
}
//排除掉不符合条件的:
//比如:["(()))(","()())(","())(()","())()("]
if(remainingLeft>remainingRight){
return;
}
//先生成左括号:(、((、(((
if(remainingLeft>0){
dfs(s+"(",remainingLeft-1,remainingRight);
}
//再生成右括号,条件不满足时会回溯
if(remainingRight>0){
dfs(s+")",remainingLeft,remainingRight-1);
}
}
}
动态规划:
//[10,9,2,5,3,7,101,18]
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums.length==0 || nums==null) return 0;
int[] dp = new int[nums.length];
int res = 0;
for(int i=0;i<nums.length;i++){
//初始化长度都为1
dp[i] = 1;
for(int j=0;j<i;j++){
// nums[i] > nums[j]时,nums[i] 可以接在 nums[j] 之后,那么长度就是原来的长度的加1
if(nums[i]>nums[j]){
dp[i] =Math.max(dp[j]+1,dp[i]);
}
}
res = Math.max(dp[i],res);
}
return res;
}
}
回溯算法:关键在于这棵树
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
dfs(nums,0,new ArrayList<Integer>());
return res;
}
private void dfs(int[] nums, int start, ArrayList<Integer> path) {
//满足条件直接添加
res.add(new ArrayList<>(path));
for(int i=start;i<nums.length;i++){
//做出选择
path.add(nums[i]);
//向树的下一层递归
dfs(nums,i+1,path);
//撤销选择
path.remove(path.size()-1);
}
}
}
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
if(nums.length==0 || nums==null) return res;
boolean[] used = new boolean[nums.length];
dfs(nums,used,new ArrayList<Integer>());
return res;
}
private void dfs(int[] nums, boolean[] used, ArrayList<Integer> path) {
if(path.size()==nums.length) {
res.add(new ArrayList<>(path));
return;
}
for(int i=0;i<nums.length;i++){
//排除掉上一层选择过的数
if(used[i]) continue;
//选择
path.add(nums[i]);
used[i] = true;
//下一层树
dfs(nums,used,path);
//撤销选择
path.remove(path.size()-1);
used[i] = false;
}
}
}
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
if(nums.length==0 || nums==null) return res;
//不排序会报错
Arrays.sort(nums);
boolean[] used = new boolean[nums.length];
dfs(nums,used,new ArrayList<Integer>());
return res;
}
private void dfs(int[] nums, boolean[] used, ArrayList<Integer> path) {
if(path.size()==nums.length){
res.add(new ArrayList<>(path));
return;
}
for(int i=0;i<nums.length;i++){
//排除掉上一层使用过的数
if(used[i]==true) {
continue;
}
//排除掉刚刚撤销的数
if(i>0 && nums[i]==nums[i-1] && used[i-1]==false){
continue;
}
path.add(nums[i]);
used[i] = true;
dfs(nums,used,path);
path.remove(path.size()-1);
used[i] = false;
}
}
}
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
if(candidates==null || candidates.length==0) return res;
//需要进行排序,方便剪枝
Arrays.sort(candidates);
dfs(candidates,target,new ArrayList<Integer>(),0);
return res;
}
private void dfs(int[] candidates, int target, ArrayList<Integer> path,int start) {
if(target==0){
res.add(new ArrayList<>(path));
}
//i=start可以去除重复解集:比如[2,3,2],[3,2,2],后面的选择的时候,前面的小数已经排除了
//当i=0时,可选的[2,3,6,7]
//当i=1时,可选的[3,6,7]
//当i=2时,可选的[6,7]
//当i=3时,可选的[7]
for(int i=start;i<candidates.length;i++){
//剪枝
if(target<candidates[i]) continue;
path.add(candidates[i]);
target = target-candidates[i];
dfs(candidates,target,path,i);
path.remove(path.size()-1);
target = target+candidates[i];
}
}
}
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
if(candidates==null ||candidates.length==0) return res;
//数组排序
Arrays.sort(candidates);
boolean[] used = new boolean[candidates.length];
dfs(candidates,used,new ArrayList<Integer>(),0,target);
return res;
}
private void dfs(int[] candidates, boolean[] used, ArrayList<Integer> path, int start,int target) {
if(target==0) {
res.add(new ArrayList<>(path));
return;
}
for(int i=start;i<candidates.length;i++){
//剪枝
if(target<candidates[i]) continue;
//上一层中使用过的排除掉
if(used[i]) continue;
//数组中存在重复元素,刚刚撤销的排除:比如 1,1,2
if(i>0 && candidates[i]==candidates[i-1] && used[i-1]==false) continue;
path.add(candidates[i]);
target = target-candidates[i];
used[i] = true;
dfs(candidates,used,path,i,target);
path.remove(path.size()-1);
target= target+candidates[i];
used[i] = false;
}
}
}
class Solution {
boolean flag = false;
public boolean exist(char[][] board, String word) {
if(board.length==0 || board==null) return false;
boolean[][] used = new boolean[board.length][board[0].length];
for(int i=0;i<=board.length-1;i++){
for(int j=0;j<=board[0].length-1;j++){
if(dfs(board,i,j,word,0,used)){
return true;
}
}
}
return false;
}
private boolean dfs(char[][] board, int i, int j, String word, int k, boolean[][] used) {
if(k==word.length()) return true;
if(i<0 || j<0 || i>=board.length || j>=board[0].length || board[i][j]!=word.charAt(k)) return false;
if(used[i][j]) return false;
//还没找到路径,继续深搜
used[i][j] = true;
boolean res1 = dfs(board,i+1,j,word,k+1,used);
boolean res2 = dfs(board,i,j+1,word,k+1,used);
boolean res3 = dfs(board,i-1,j,word,k+1,used);
boolean res4 = dfs(board,i,j-1,word,k+1,used);
//找到路径
if(res1|| res2|| res3||res4) {
flag = true;
}else{
//每找到,撤销选择
used[i][j] = false;
}
return flag;
}
}
使用递归:但是会使用if,所以不满足条件
class Solution {
int res = 0;
public int sumNums(int n) {
if(n==1) return 1;
res = res +sumNums(n-1);
return res;
}
}
将if条件去掉:
class Solution {
public int sumNums(int n) {
boolean x = n>1 && (n+=sumNums(n-1))>0;
return n;
}
}
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//如果根节点的值比两个节点的值都大,就从左子树找
if(root.val>p.val && root.val >q.val) return lowestCommonAncestor(root.left,p,q);
//如果根节点的值比两个节点的值都小,就从右子树找
if(root.val<p.val && root.val<q.val) return lowestCommonAncestor(root.right,p,q);
//否则返回根节点
return root;
}
}
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null || root==p || root==q) return root;
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
if(left==null && right==null) return null;
if(left==null) return right;
if(right==null) return left;
return root;
}
}
class Solution {
public int minDepth(TreeNode root) {
if(root==null) return 0;
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
//如果左右子树有一方为null
if(root.left==null || root.right==null){
return leftDepth+rightDepth+1;
}
return Math.min(leftDepth,rightDepth)+1;
}
}
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 MyQueue {
Stack A;
Stack B;
/** Initialize your data structure here. */
public MyQueue() {
A = new Stack<>();
B = new Stack<>();
}
/**
* 1、使用两个栈,一个栈(stackPush)用于元素进栈,一个栈(stackPop)用于元素出栈;
* 2、pop() 或者 peek() 的时候:
* (1)如果 stackPop 里面有元素,直接从 stackPop 里弹出或者 peek 元素;
* (2)如果 stackPop 里面没有元素,一次性将 stackPush 里面的所有元素倒入 stackPop。
*/
public void push(int x) {
A.push(x);
}
public int pop() {
if(!B.isEmpty()) return B.pop();
while (!A.isEmpty()){
B.push(A.pop());
}
return B.pop();
}
public int peek() {
if(!B.isEmpty()) return B.peek();
while (!A.isEmpty()){
B.push(A.pop());
}
return B.peek();
}
public boolean empty() {
return A.isEmpty() && B.isEmpty();
}
}
class Solution {
public int search(int[] nums, int target) {
if(nums.length==0 || nums==null){
return 0;
}
int start = 0;
int end = nums.length-1;
while (start+1<end){
int mid = start+(end-start)/2;
if(target>nums[mid]){
start = mid;
}else{
end = mid;
}
}
if(nums[start]==target) return start;
if(nums[end]==target) return end;
return -1;
}
}
class Solution {
public int search(int[] nums, int target) {
if(nums.length==0 || nums==null ){
return 0;
}
int start = 0;
int end = nums.length-1;
while (start+1<end){
int mid = start+(end-start)/2;
//如果前半段是递增的
if(nums[start]<=nums[mid]){
if(nums[start]<=target && target<=nums[mid]){
end=mid;
}else{
start = mid;
}
}else{
if(nums[mid]<=target && target<=nums[end]){
start = mid;
}else{
end = mid;
}
}
}
if(nums[start]==target) return start;
if(nums[end]==target) return end;
return -1;
}
}
class Solution {
public int findMin(int[] nums) {
if(nums.length==0 || nums==null) return 0;
int start = 0;
int end = nums.length-1;
while (start+1<end){
int mid = start+(end-start)/2;
if(nums[mid]>nums[end]){
start = mid;
}else if(nums[mid]<nums[end]){
end = mid;
//别忘记相等的时候 1122222333
}else if(nums[mid]==nums[end]){
end--;
}
}
//防止出现 1这种情况,end和start指向同一个数
if(nums[start]>nums[end]) {
return nums[end];
}else{
return nums[start];
}
}
}
class Solution {
public int searchInsert(int[] nums, int target) {
if(nums.length==0 || nums==null){
return 0;
}
int start = 0;
int end = nums.length-1;
while (start+1<end){
int mid = start + (end-start)/2;
if(target>nums[mid]){
start = mid;
}else{
end = mid;
}
}
if(nums[start]==target) return start;
if(nums[end]==target) return end;
if(nums[start]<target && target<nums[end]){
return end;
}else if(nums[start]>target){
return start;
//注意是return end+1
}else {
return end+1;
}
}
}
class Solution {
public boolean isSubtree(TreeNode s, TreeNode t) {
if(s==null && t==null) return true;
if(s==null || t==null) return false;
return dfs(s,t) || isSubtree(s.left,t) || isSubtree(s.right,t);
}
private boolean dfs(TreeNode s, TreeNode t) {
if(s==null && t==null) return true;
if(s==null || t==null ) return false;
return s.val==t.val && dfs(s.left,t.left) && dfs(s.right,t.right);
}
}
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root==null) return null;
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
invertTree(root.left);
invertTree(root.right);
return root;
}
}
class Solution {
//一个节点的最大直径 = 它左树的高度 + 它右树的高度
//然后其实就是遍历每个节点,找出所有节点中的直径的最大值即可。
/**
* 4 可得加点4的直径为2,因为任意两个节点之间的边的数目就是直径,1和2的节点间边的数目2,经过节点4
* /\
* 1 2
*/
int max = 0;
public int diameterOfBinaryTree(TreeNode root) {
if(root==null) return 0;
dfs(root);
return max;
}
private int dfs(TreeNode root) {
if(root==null) return 0;
int leftDepth = dfs(root.left);
int rightDepth = dfs(root.right);
max = Math.max(max,leftDepth+rightDepth);
return Math.max(leftDepth,rightDepth)+1;
}
}
class Solution {
public int maxArea(int[] height) {
//使用双指针,计算两个板子围成的面积,面积=两个板子之间的距离*短板的高度,因此从两边向内移动短板
int left = 0;
int right = height.length-1;
int area =0;
//计算围成面积的最大值
int res = 0;
while (left<right){
area = Math.min(height[left],height[right])*(right-left);
res = Math.max(res,area);
if(height[left]<height[right]){
left++;
}else{
right--;
}
}
return res;
}
}
class Solution {
public boolean isPalindrome(int x) {
//负数和10、100、1000这样的数一定不是回文数,但是0是回文数
if(x<0 || (x%10==0 && x!=0)){
return false;
}
//如果是回文数,将这个数反转后一定和原来的数相同
int tmp = x;
int reverse = 0;
while (x>0){
reverse = reverse*10+(x%10);
x = x/10;
}
return reverse==tmp;
}
}
class Solution {
// 1 1 2 3 3 3 4 5 6
public int removeDuplicates(int[] nums) {
//原地移动,用一个指针用来排除重复元素,因为nums[0]一定保留,所以从1开始
int count = 1;
for(int i=1;i<nums.length;i++){
//后面的数和count指针指向的数不相等,就将后面的数向count位置移动,相等则不动
if (nums[i]!=nums[i-1]){
nums[count++] = nums[i];
}
}
return count;
}
}
class Solution {
public double myPow(double x, int n) {
if(n>0){
return pow(x,n);
}else{
return 1/pow(x,n);
}
}
private double pow(double x, int n) {
if(n==0) return 1;
double y = pow(x,n/2);
if(n%2==0){
return y*y;
}else{
return y*y*x;
}
}
}
class Solution {
public int reverse(int x) {
long res = 0;
//注意,x只能写成不等于0,不能写成>0,因为包含负数
while (x!=0){
res = res * 10 +x%10;
x=x/10;
}
if(res>Integer.MAX_VALUE || res <Integer.MIN_VALUE){
return 0;
}
return (int) res;
}
}