牛客算法刷题
文章目录
前言
一、链表
1.反转链表
描述:
给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。
代码如下(示例):
方法一:
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @return ListNode类
*/
public ListNode ReverseList (ListNode head) {
// write code here
ListNode pre = null;
ListNode temp = null;
while(head != null){
temp = head.next;
head.next = pre;
pre = head;
head = temp;
}
return pre;
}
2.链表内指定区间反转
描述:将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度O(n),空间复杂度O(1)。
代码如下(示例):
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @param m int整型
* @param n int整型
* @return ListNode类
*/
public ListNode reverseBetween (ListNode head, int m, int n) {
// write code here
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
for(int i = 1; i <m; i++){
pre = pre.next;
}
ListNode cur = pre.next;
ListNode temp;
for(int i = m; i < n; i ++){
temp = cur.next;
cur.next = temp.next;
temp.next = pre.next;
pre.next = temp;
}
return dummy.next;
}
3.合并两个排序的链表
描述:输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。
代码如下(示例):
方法一:
public class Solution {
/**
* 一般解法
*
*
* @param pHead1 ListNode类
* @param pHead2 ListNode类
* @return ListNode类
*/
public ListNode Merge (ListNode pHead1, ListNode pHead2) {
// write code here
if(pHead1 ==null){
return pHead2;
}
if(pHead2 == null){
return pHead1;
}
ListNode dummy = new ListNode(0);
ListNode list = dummy;
while(pHead1 != null && pHead2 != null){
if(pHead1.val >= pHead2.val){
list.next = pHead2;
pHead2 = pHead2.next;
}else if(pHead1.val < pHead2.val){
list.next = pHead1;
pHead1 = pHead1.next;
}
list = list.next;
}
if(pHead1 == null){
list.next = pHead2;
}
if(pHead2 == null){
list.next = pHead1;
}
return dummy.next;
}
方法二:
public class Solution {
/**
* 递归法
*
*
* @param pHead1 ListNode类
* @param pHead2 ListNode类
* @return ListNode类
*/
public ListNode Merge (ListNode pHead1, ListNode pHead2) {
// write code here
if(pHead1 ==null){
return pHead2;
}
if(pHead2 == null){
return pHead1;
}
ListNode list = null;
if(pHead1.val >= pHead2.val){
list = pHead2;
list.next = Merge(pHead1,pHead2.next);
}else if(pHead1.val < pHead2.val){
list = pHead1;
list.next = Merge(pHead1.next,pHead2);
}
return list;
}
4.判断链表中是否有环
描述:判断给定的链表中是否有环。如果有环则返回true,否则返回false。
代码如下(示例):
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null){
return false;
}
ListNode fast = head;
ListNode slow = head;
while(slow.next != null && fast.next != null && fast.next.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast== slow){
return true;
}
}
return false;
}
4.链表中环的入口结点
描述:给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
代码如下(示例):
方法一:
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
if(pHead == null){
return null;
}
ListNode fast = pHead;
ListNode slow = pHead;
while(fast.next != null && fast.next.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
slow = pHead;
while(slow != fast){
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
return null;
}
方法二:
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
// ArrayList<ListNode> listNodes = new ArrayList<>();
// HashMap<ListNode,Boolean> Map = new HashMap<>();
HashSet<ListNode> set = new HashSet<>();
while(pHead != null){
if(set.contains(pHead)){
return pHead;
}
set.add(pHead);
pHead = pHead.next;
}
return null;
}
5.链表中倒数最后k个结点
描述:输入一个长度为 n 的链表,设链表中的元素的值为 ai ,返回该链表中倒数第k个节点。
如果该链表长度小于k,请返回一个长度为 0 的链表。
代码如下(示例):
方法一:
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pHead ListNode类
* @param k int整型
* @return ListNode类
*/
public ListNode FindKthToTail (ListNode pHead, int k) {
// write code here
if(pHead == null){
return null;
}
ListNode fast = pHead;
while(fast != null && k > 0 ){
fast = fast.next;
k = k-1;
}
if(k > 0){
return null;
}
ListNode slow = pHead;
while(fast != null){
slow = slow.next;
fast = fast.next;
}
return slow;
}
方法二:
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* @param pHead ListNode类
* @param k int整型
* @return ListNode类
*/
public ListNode FindKthToTail (ListNode pHead, int k) {
// write code here
if(pHead == null){
return null;
}
ListNode fast = pHead;
int i = 0;
while(fast != null){
fast = fast.next;
i = i+1;
}
if(i-k < 0){
return null;
}
ListNode slow = pHead;
for(int j = 0; j < i-k; j++){
slow = slow.next;
}
return slow;
}
6.两个链表的第一个公共结点
描述:输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。
例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:可以看到它们的第一个公共结点的结点值为6,所以返回结点值为6的结点。
代码如下(示例):
使用两个指针N1,N2,一个从链表1的头节点开始遍历,我们记为N1,一个从链表2的头节点开始遍历,我们记为N2。
让N1和N2一起遍历,当N1先走完链表1的尽头(为null)的时候,则从链表2的头节点继续遍历,同样,如果N2先走完了链表2的尽头,则从链表1的头节点继续遍历,也就是说,N1和N2都会遍历链表1和链表2。
因为两个指针,同样的速度,走完同样长度(链表1+链表2),不管两条链表有无相同节点,都能够到达同时到达终点。
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1 == null || pHead2 == null){
return null;
}
ListNode p1 = pHead1;
ListNode p2 = pHead2;
while(p1 != p2){
p1 = (p1 == null ? pHead2 : p1.next);
p2 = (p2 == null ? pHead1 : p2.next);
}
return p1;
}
7.链表相加(二)
描述:假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。给定两个这种链表,请生成代表两个整数相加值的结果链表。
例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。
代码如下(示例):
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head1 ListNode类
* @param head2 ListNode类
* @return ListNode类
*/
public ListNode addInList (ListNode head1, ListNode head2) {
// write code here
ListNode list1 = getReturnList(head1);
ListNode list2 = getReturnList(head2);
int n = 0;
ListNode result = new ListNode(-1);
ListNode pre = result;
while(list1 != null || list2 != null || n != 0){
if(list1 != null){
n = n + list1.val;
list1 = list1.next;
}
if(list2 != null){
n = n + list2.val;
list2 = list2.next;
}
//取余
pre.next = new ListNode(n % 10);
//指针移位
pre = pre.next;
//取整进位
n = n / 10;
}
return getReturnList(result.next);
}
//反转链表
private ListNode getReturnList(ListNode node){
if(node == null || node.next == null){
return node;
}
ListNode pre = null, temp;
while(node != null){
temp = node.next;
node.next = pre;
pre = node;
node = temp;
}
return pre;
}
8.单链表的排序
描述:给定一个节点数为n的无序单链表,对其按升序排序。
代码如下(示例):
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* @param head ListNode类 the head node
* @return ListNode类
*/
public ListNode sortInList (ListNode head) {
// write code here
ArrayList<Integer> list = new ArrayList();
while(head != null){
list.add(head.val);
head = head.next;
}
Collections.sort(list);
ListNode root = new ListNode(0);
ListNode cur = root;
for (int i = 0; i < list.size(); i++){
cur.next = new ListNode(list.get(i));
cur = cur.next;
}
return root.next;
}
9.单链表的排序
描述:给定一个链表,请判断该链表是否为回文结构。回文是指该字符串正序逆序完全一致。
代码如下(示例):
方法一:
public class Solution {
/**
* 利用堆栈法
* @param head ListNode类 the head
* @return bool布尔型
*/
public boolean isPail (ListNode head) {
// write code here
Stack<ListNode> stack = new Stack<>();
ListNode node = head;
while(node != null){
stack.push(node);
node = node.next;
}
while(head != null){
if(head.val != stack.pop().val){
return false;
}
head = head.next;
}
return true;
}
方法二:
public class Solution {
/**
* 利用双指针法
* @param head ListNode类 the head
* @return bool布尔型
*/
public boolean isPail (ListNode head) {
// write code here
if(head == null || head.next == null){
return true;
}
ListNode slow = head, fast = head;
while (fast.next != null && fast.next.next != null){
slow = slow.next;
fast = fast.next.next;
}
ListNode mid = getReturnList(slow.next);
while(mid != null && head != null){
if(head.val != mid.val){
return false;
}
head = head.next;
mid = mid.next;
}
return true;
}
private ListNode getReturnList(ListNode list){
if(list == null || list.next == null)
return list;
ListNode pre = null,temp;
while(list != null){
temp = list.next;
list.next = pre;
pre = list;
list = temp;
}
return pre;
}
10.链表的奇偶重排
描述:给定一个单链表,请设定一个函数,将链表的奇数位节点和偶数位节点分别放在一起,重排后输出。注意是节点的编号而非节点的数值。
代码如下(示例):
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* @param head ListNode类
* @return ListNode类
*/
public ListNode oddEvenList (ListNode head) {
// write code here
if(head == null || head.next == null){
return head;
}
ListNode list1 = head, list2 = head.next, list2Head = list2;
while(list2 != null && list2.next != null){
list1.next = list2.next;
list1 = list1.next;
list2.next = list1.next;
list2 = list2.next;
}
list1.next = list2Head;
return head;
}
11.删除有序链表中重复的元素-I
描述:删除给出链表中的重复元素(链表中元素从小到大有序),使链表中的所有元素都只出现一次.
代码如下(示例):
方法一:
public class Solution {
/**
* @param head ListNode类
* @return ListNode类
*/
public ListNode deleteDuplicates (ListNode head) {
// write code here
if(head == null || head.next == null){
return head;
}
ListNode pre = head;
while (pre != null && pre.next != null){
if(pre.val == pre.next.val){
pre.next = pre.next.next;
}else{
pre = pre.next;
}
}
return head;
}
12.删除有序链表中重复的元素-I
描述:给出一个升序排序的链表,删除链表中的所有重复出现的元素,只保留原链表中只出现一次的元素。
代码如下(示例):
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @return ListNode类
*/
public ListNode deleteDuplicates (ListNode head) {
// write code here
ListNode newList = new ListNode(-1);
newList.next = head;
ListNode pre = newList;
while (pre.next != null && pre.next.next != null) {
int val = pre.next.next.val;
if(pre.next.val == val){
while(pre.next != null && pre.next.val == val){
pre.next = pre.next.next;
}
}else{
pre = pre.next;
}
}
return newList.next;
}
总结
坚持每天刷题!!!(打卡第2天)