1.二分查找右边界:爱吃香蕉的珂珂
class Solution {
public int minEatingSpeed(int[] piles, int h) {
//使用二分查找法寻找速度的左边界,即最小速度
//速度的左右边界,最大速度就是数组的最大值,因为一小时吃完这堆香蕉不会再吃更多的香蕉
int left=1,right=getMax(piles)+1;
while(left<right){
int mid=left+(right-left)/2;
if(canEatAll(piles,mid,h)){
right=mid;
}else{
left=mid+1;
}
}
return left;
}
//求速度为speed时,吃完香蕉需要的时间总和是否小于等于时间h
//在满足这个条件的速度里使用二分查找找到最小速度
public boolean canEatAll(int[] piles,int speed,int h){
int res=0;
for(int pile:piles){
res=res+(pile/speed)+((pile%speed==0)?0:1);
}
return res<=h;
}
//求最大值
public int getMax(int[] piles){
int res=0;
for(int i:piles){
res=Math.max(res,i);
}
return res;
}
}
2.快慢双指针+hashset:环形链表
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
//1.使用快慢双指针
ListNode slow=head,fast=head;
while(fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow){
return true;
}
}
return false;
//2.使用hashset
// Set<ListNode> set=new HashSet<>();
// while(head!=null){
// if(set.contains(head)){
// return true;
// }
// set.add(head);
// head=head.next;
// }
// return false;
}
}
3.快慢双指针:环形链表2
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head!=null && head.next==null){
return null;
}
ListNode slow=head,fast=head;
while(fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow) break;//找到环的入口
}
//如果没有环,则经过while循环之后fast和slow指向位置不同,则返回null
if(fast!=slow){
return null;
}
//寻找环的入口
//如果是环形链表带小尾巴,就会进入while循环寻找环的入口;
//如果不带尾巴,则上个while循环fast和slow总会在入口处(head)相遇:因为fast速度是slow的二倍,相遇时fast走了两圈,slow走了一圈,相遇处就是head,则不会进入下面的while循环。
fast=head;
while(fast!=slow){
fast=fast.next;
slow=slow.next;
}
return fast;
}
}
4.快慢双指针:链表的中间节点
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode middleNode(ListNode head) {
ListNode fast=head,slow=head;
while(fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
}
return slow;
}
}
5.快慢双指针:链表中倒数第k个节点
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
if(head==null){
return null;
}
//防止k超过链表长度
int len=0;
ListNode temp=head;
while(temp!=null){
temp=temp.next;
len++;
}
if(k!=len){
k=k%len;
}
ListNode fast=head,slow=head;
//fast先走k步
while(k>0){
fast=fast.next;
k--;
}
//一起走,最后slow的位置就是倒数第k个节点
while(fast!=null){
fast=fast.next;
slow=slow.next;
}
return slow;
}
}
6.快慢双指针:删除有序数组中的重复项
class Solution {
public int removeDuplicates(int[] nums) {
//使用快慢指针,快指针遇到不同的数就和慢指针交换,最后慢指针以及慢指针之前的数组部分都是不重复的
int n=nums.length;
int fast=0,slow=0;
while(fast<n){
if(nums[fast]!=nums[slow]){
slow++;
nums[slow]=nums[fast];
}
fast++;
}
return slow+1;
}
}
7.快慢双指针:删除排序链表中的重复元素
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head==null) return null;
ListNode fast=head,slow=head;
while(fast!=null){
if(fast.val!=slow.val){
slow.next=fast;
slow=slow.next;
}
fast=fast.next;
}
slow.next=null;//处理末尾
return head;
}
}
8.快慢双指针:移除元素
class Solution {
public int removeElement(int[] nums, int val) {
int n=nums.length;
if(n==0) return 0;
int fast=0,slow=0;
while(fast<n){
if(nums[fast]!=val){
nums[slow]=nums[fast];
slow++;
}
fast++;
}
return slow;
}
}
9.快慢双指针:移动零
class Solution {
public void moveZeroes(int[] nums) {
int n=nums.length;
if(n==0) return;
int fast=0,slow=0;
while(fast<n){
if(nums[fast]!=0){
int temp=nums[slow];
nums[slow]=nums[fast];
nums[fast]=temp;
slow++;
}
fast++;
}
}
}
10.hashmap:两数之和
class Solution {
public int[] twoSum(int[] nums, int target) {
//使用hashmap
int[] res=new int[2];
Map<Integer,Integer> map=new HashMap<>();
for(int i=0;i<nums.length;i++){
if(map.containsKey(target-nums[i])){
res[0]=map.get(target-nums[i]);
res[1]=i;
break;
}
map.put(nums[i],i);
}
return res;
}
}
11.左右双指针+字符串:整数反转
class Solution {
public int reverse(int x) {
String s=String.valueOf(x);
char[] c=s.toCharArray();
int n=s.length();
int left=0,right=n-1;
if(c[0]=='-'){
left=1;
}
while (left<=right){
char temp=c[left];
c[left]=c[right];
c[right]=temp;
left++;
right--;
}
s=String.valueOf(c);
if(Double.valueOf(s)>(Math.pow(2,31)-1) || Double.valueOf(s)<(-Math.pow(2,31))){
return 0;
}else{
return Integer.valueOf(s);
}
}
}