8月9日算法刷题
- 一、排序
- 1. 成绩排序(清华大学考研机试题)
- 考点:结构体排序
- 在结构体中定义排序
- 使用比较器定义排序
- 注意问题:需要处理 值相等时 先后顺序
- 2. 成绩排序2( 清华大学考研机试题 )
- 1. 从尾到头打印链表
- 本题考点
- 栈
- 2. 在O(1)时间删除链表结点
- 3. 删除链表中重复的节点
- 总结:删除节点的两种方法
- 1. a-》b 直接让a的值等于b的值,a的next等于b的next
- 2. a-》b-》c 让a的next指向c(只有修改next才管用)
- java版本(画个草图就知道怎么做了 并且 java没有指针)
- 4. 链表中倒数第k个节点
- 遍历两次
- 遍历一次(需要再开一个指针而已)但是本题不行,因为题目有长度限制,我们需要先知道链表长度
一、排序
1. 成绩排序(清华大学考研机试题)
考点:结构体排序
在结构体中定义排序
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int n, m;
struct Person
{
string name;
int score;
int id;
bool operator< (const Person& t) const
{
if (score != t.score) return score < t.score;
return id < t.id;
}
bool operator> (const Person& t) const
{
if (score != t.score) return score > t.score;
return id < t.id;
}
}q[N];
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i ++ )
{
cin >> q[i].name >> q[i].score;
q[i].id = i;
}
if (!m) sort(q, q + n, greater<Person>());
else sort(q, q + n);
for (int i = 0; i < n; i ++ )
cout << q[i].name << ' ' << q[i].score << endl;
return 0;
}
使用比较器定义排序
#include<bits/stdc++.h>
using namespace std;
struct node{
int x,id;
string name;
}a[1001];
bool cmp1(node a,node b){
//从小到大
if(a.x==b.x)return a.id<b.id;
return a.x<b.x;
}
bool cmp2(node a,node b){
//从大到小
if(a.x==b.x)return a.id<b.id;
return a.x>b.x;
}
int main()
{
int n;
bool ok;
cin>>n>>ok;
for(int i=1;i<=n;i++){
cin>>a[i].name>>a[i].x;
a[i].id=i;
}
if(ok)sort(a+1,a+1+n,cmp1);
if(!ok)sort(a+1,a+1+n,cmp2);
for(int i=1;i<=n;i++)
cout<<a[i].name<<' '<<a[i].x<<'\n';
}
注意问题:需要处理 值相等时 先后顺序
在结构体中定义一个id,记录出现的顺序
// package Test;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Scanner;
/**
* @Author zh
* @Date 2023/8/8 19:10
* @PackageName:Test
* @ClassName: Main
* @Description: TODO
* @Version 1.0
*/
class Student{
int grade;
String name;
public Student(int grade,String name){
this.grade = grade;
this.name = name;
}
}
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
int a = scanner.nextInt();
Student[] students = new Student[N];
for(int i = 0; i < N; i++){
String name = scanner.next();
int grade = scanner.nextInt();
students[i] = new Student(grade,name);
}
if(a == 1){
Arrays.sort(students,(o1, o2) -> {
return o1.grade-o2.grade;
});
}else{
Arrays.sort(students,(o1, o2) -> {
return o2.grade-o1.grade;
});
}
for(Student x : students){
System.out.println(x.name + " " + x.grade);
}
}
}
2. 成绩排序2( 清华大学考研机试题 )
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int n;
struct Person
{
int id;
int score;
bool operator< (const Person& t) const
{
if (score != t.score) return score < t.score;
return id < t.id;
}
}q[N];
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> q[i].id >> q[i].score;
sort(q, q + n);
for (int i = 0; i < n; i ++ ) cout << q[i].id << ' ' << q[i].score << endl;
return 0;
}
import java.util.Arrays;
import java.util.Scanner;
class Student{
int id;
int grade;
public Student(int id,int grade){
this.id = id;
this.grade = grade;
}
}
class Main{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
Student[] students = new Student[n];
for(int i = 0; i < n; i++){
int id = scanner.nextInt();
int grade = scanner.nextInt();
students[i] = new Student(id,grade);
}
Arrays.sort(students,(o1, o2) -> {
if(o1.grade == o2.grade){
return o1.id-o2.id;
}
return o1.grade-o2.grade;
});
for (Student x : students){
System.out.println(x.id + " " + x.grade);
}
}
}
1. 从尾到头打印链表
原题链接
原题链接
本题考点
- 顺序打印链表的掌握(简单)
- 数组的翻转reverse
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
#include<algorithm>
class Solution {
public:
vector<int> printListReversingly(ListNode* head) {
vector<int> res;
while (head) {
res.push_back(head->val);
head = head->next;
}
reverse(res.begin(),res.end());
return res;
}
};
栈
/**
* @author bingo
* @since 2018/12/19
*/
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
/**
* 从尾到头打印链表
*
* @param head 链表头结点
* @return 结果数组
*/
public int[] printListReversingly(ListNode head) {
if (head == null) {
return null;
}
Stack<Integer> stack = new Stack<>();
ListNode cur = head;
int cnt = 0;
while (cur != null) {
stack.push(cur.val);
cur = cur.next;
++cnt;
}
int[] res = new int[cnt];
int i = 0;
while (!stack.isEmpty()) {
res[i++] = stack.pop();
}
return res;
}
}
2. 在O(1)时间删除链表结点
原题链接
所给的是要删除的节点
那么我们把要删除的节点的指等于下一个指
所指向的地址等于下一个所指向的地址
这样就把该节点删除了
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
node->val = node->next->val;
node->next = node->next->next;
}
};
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public void deleteNode(ListNode node) {
node.val = node.next.val;
node.next = node.next.next;
}
}
3. 删除链表中重复的节点
原题链接
本题需要注意:
- 增加一个空的头节点,便于删除第一个节点(如果要删除的话)
- 如何删除一串节点?必须找到先前一个节点,令先前的节点的next指向要删除一串的后面的那一个
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* head) {
auto dummy = new ListNode(-1); //建立虚拟头结点
dummy->next = head;//虚拟头结点指向头结点
auto p = dummy;
while(p->next) //p的下一个节点不为空
{
auto q = p->next;
//q的下一个节点不为空,且q的下一个节点的值等于p的下一个节点的值
while(q->next && q->next->val == p->next->val) q= q->next;
//如果q==p的下一个节点 p=q
if(q==p->next) p=q;
//如果不是说明存在重复元素,则p指向q的下一个节点即非重复节点
else p->next = q->next;
}
return dummy->next;
}
}
总结:删除节点的两种方法
1. a-》b 直接让a的值等于b的值,a的next等于b的next
2. a-》b-》c 让a的next指向c(只有修改next才管用)
java版本(画个草图就知道怎么做了 并且 java没有指针)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode deleteDuplication(ListNode head) {
if(head == null)
return null;
if(head.next == null)
return head;
ListNode l = null;
ListNode l1 = head;
ListNode l2 = head.next;
while(l2!=null){
if(l1.val != l2.val){
l = l1;
l1 = l2;
l2 = l2.next;
} else {
while(l2 != null && l1.val == l2.val){
l2 = l2.next;
}
if(l2 == null){
if(l == null)
return null;
l.next = null;
break;
} else {
if(l == null){
head = l2;
l1 = l2;
l2 = l2.next;
continue;
}
l.next = l2;
l1 = l2;
l2 = l2.next;
}
}
}
return head;
}
}
4. 链表中倒数第k个节点
原题链接
遍历两次
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* findKthToTail(ListNode* head, int k) {
int n = 0;
for (auto p = head; p; p = p->next) n ++ ;
if (n < k) return nullptr;
auto p = head;
for (int i = 0; i < n - k; i ++ ) p = p->next;
return p;
}
};
遍历一次(需要再开一个指针而已)但是本题不行,因为题目有长度限制,我们需要先知道链表长度
class Solution {
public:
ListNode* findKthToTail(ListNode* p, int k) {
auto *n = p;
while (n && k) n = n -> next, -- k;
if (k) return nullptr;
while (n) p = p -> next, n = n -> next;
return p;
}
};
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode findKthToTail(ListNode pListHead, int k) {
if (k == 0) return null;
int len = cmpLen(pListHead);
if (k > len) return null;
int count = 0;
ListNode cur = pListHead;
while (count != (len - k)) {
cur = cur.next;
count++;
}
return cur;
}
private int cmpLen(ListNode pListHead) {
ListNode cur = pListHead;
int count = 0;
while (cur != null) {
count++;
cur = cur.next;
}
return count;
}
}