大家好!我是未来村村长,就是那个“请你跟我这样做,我就跟你这样做!”的村长👨?🌾!
||Algorithm Day||
? 未来村村长正推出一系列【Algorithm Day】文章,该系列文章重在提高本人的算法能力,希望能在刷题过程中总结一般方法,提高个人的逻辑思维能力和解题能力。该系列文章以天数为轴,从一个个算法中逐步强化算法相关知识点。
? ”算法之路,任重而道远。“🌱[day 1]🌾
? 此篇文章包含三个算法:反转链表、快速排序、二分查找
? [声明:以下题目的内容或部分解法来自牛客网或Leetcode,为个人学习总结和记录,也方便大家学习和查阅]
一、反转单链表
1、题目描述
(1)描述
给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。
数据范围: n∈[0,1000]
要求:空间复杂度 O(1),时间复杂度 O(n)。
(2)示例
例子:
如当输入链表{1,2,3}时,
经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。
2、思路分析
(1)实现一思路
? 使用栈,将链表节点一个个入栈,当全部入栈后再一个个出栈
Stack<ListNode> stack= new Stack<>();
(2)实现二思路
? 将原链表的结点从头开始摘掉,每次摘得的节点都让它成为新的链表头结点
3、Java实现
(1)方法一:使用栈
import java.util.Stack;
public class Solution {
public ListNode ReverseList(ListNode head) {
Stack<ListNode> stack = new Stack<>();
while(Head != null){
stack.push(head);
head = head.next;
}
if(stack.isEmpty()) return null;
ListNode newHead = stack.pop();
ListNode temp = newHead;
while(!stack.isEmpty()){
temp.next = stack.pop();
temp = temp.next;
}
temp.next = null;
return newHead;
}
}
(2)方法二:逐个摘出为新头
? 相当于是两个链表,一个从头取出,然后从头插入另一个链表
public class Solution {
public ListNode ReverseList(ListNode head) {
ListNode newHead = null;
while( head != null){
ListNode temp = head.next;
head.next = newHead;
newHead = head;
head = temp;
}
return newHead;
}
}
4、相关知识补充【常用数据结构】
(1)栈Stack
? 创建
Stack<Object> stack= new Stack<>();
常用方法 | 说明 |
---|
peek() | 查询栈顶元素 | pop() | 取出栈顶元素,并返回该元素 | push() | 往栈顶加元素 | search() | 返回元素在栈中位置,最小为1 | isEmpty() | 返回是否为空,elementCount == 0 |
(2)队列Queue
? 创建
LinkedList<Object> list = new LinkedList<>();
常用方法 | 说明 |
---|
peek() | 获取队头元素(不删除) | offfer() | 入队 | poll() | 出队 | isEmpty() | 返回是否为空 | peekLast() | 取最后一个节点的元素 | offerFirst() | 往队列的前面插入元素 |
(3)堆
? 堆其实就是一种特殊的队列——优先队列。
? 这篇说得好:https://blog.csdn.net/u010285974/article/details/107712892
? 二叉堆是基于完全二叉树实现,其有两种类型:
-
大顶堆:每个节点的关键字都大于其孩子节点的关键字,根节点是堆中最大节点【因为双亲节点总是大于孩子节点,所以从根节点出发,无论走那条路,得到的都是一个递减序列,可证明根节点为堆中最大节点】 -
小顶堆:每个节点的关键字都小于其孩子节点的关键字,根节点是堆中最小节点 通过数组建造大顶堆,就是通过sink算法,将数组每个元素进行下沉操作
private static void sink(int[] arr,int index,int length){
int leftChild = 2*index + 1;
int rightChild = 2*index + 2;
int present = index;
if(leftChild<length && arr[leftChild]>arr[present]){
present = leftChild;
}
if(rightChild<length && arr[rightChild]>arr[present]){
present = rightChild;
}
if(present!=index){
int temp = arr[index];
arr[index] = arr[present];
arr[present] = temp;
sink(arr,present,length);
}
? 建造堆。
private static void buildHeap(int[] arr,int length){
for (int i = length/2; i>=0; i--) {
sink(arr,i,length);
}
}
二、排序
1、题目描述
(1)描述
? 给定一个长度为 n 的数组,请你编写一个函数,返回该数组按升序排序后的结果。
? 要求:时间复杂度 O(n2),空间复杂度 O(n)
? 进阶:时间复杂度 O(nlogn),空间复杂度 O(n)
(2)示例
?
2、思路分析
(1)实现一思路
? 使用Arrays.sort
Arrays.sort(arr);
(2)实现二思路
? 快速排序:快速排序采用的是分治的思想,不断递归【设定一个基准位,将该数组分成两份】,实现数组的排序。
3、Java实现
(1)实现一:Arrays
import java.util.*;
public class Solution {
public int[] MySort (int[] arr) {
Arrays.sort(arr);
return arr;
}
}
(二)实现二:快排
import java.util.*;
public class Solution {
public int[] MySort (int[] arr) {
QSort(arr,0,arr.length-1);
return arr;
}
public void QSort (int[] arr,int low,int high) {
int i,j;
if(low>high) return;
i = low;
j = high;
int temp = arr[low];
while (i<j){
while (arr[j]>=temp && j>i) j--;
while (arr[i]<=temp && j>i) i++;
if(j>i){
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
arr[low] = arr[i];
arr[i] = temp;
QSort(arr,low,j-1);
QSort(arr,j+1,high);
}
}
4、相关知识补充【Arrays的使用】
(1)Arrays的常用方法
常用方法 | 说明 |
---|
sort(arr) | 进行数组的排序,可对String数组进行排序。反向排序。 | sort(strArray, Collections.reverseOrder()) | 反向排序 | sort(arr,index1,index2); | 选择数组指定位置进行排序 | toString(arr) | 将数组中的内容转换为字符串 | equals(arr) | 比较数组元素是否相等 | binarySearch(arr,index) | 二分查找法找指定元素的索引值(下标),数组一定是排好序的,否则会出错。 | copyOf(arr, index) | 截取数组(从0到index) | copyOfRange(arr,index1,index2) | 截取数组(从index1到index2) | fill(Object[ ] array, Object obj) | 指定元素填充整个数组(替换数组原元素) |
三、二分查找
1、题目描述
(1)描述
? 请实现有重复数字的升序数组的二分查找
? 给定一个 元素有序的(升序)长度为n的整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的第一个出现的target,如果目标值存在返回下标,否则返回 -1
? 进阶:时间复杂度O(logn) ,空间复杂度O(n)
(2)示例
2、思路分析
? ① 使用while循环来实现二分查找,将目标数值与数组中心数进行比较。
? ② 如果目标数大于中心数,则又从右边取中心数进行比较;如果目标数大于中心数,则又从左边取中心数进行比较,直到数组中心数等于目标数。
? ③ 此时可能还有首次出现的数在中心数的左边,这时向左遍历看是否有相同的值。
3、Java实现
import java.util.*;
public class Solution {
public int search (int[] nums, int target) {
int l = nums.length;
if(l==0 || nums[0]>target || nums[l-1]<target) return -1;
int i = 0,j = l-1,mid = 0;
while(i<=j){
mid = (i+j)/2;
if(target>nums[mid]) i = mid + 1;
if(target<nums[mid]) j = mid - 1;
if(target==nums[mid]){
while(mid>0 && nums[mid-1]==target) mid--;
return mid;
}
}
return -1;
}
}
4、相关知识补充
? 由二分查找可以拓展到二叉查找树,由二叉查找树可以拓展到B树,然后到红黑树,之后到B+树。
|