本题解只是参考答案,思路并不唯一!!!
A题 存款利息
方法一
本题主要考察循环语句,题目较为简单,直接看代码
C语言
#include <stdio.h>
int main()
{
double money_1,money_2;
scanf("%lf", &money_1);
money_2 = money_1;
money_1 += money_1 * 4 * 0.0275; //存四年,复利计息
for (int i = 0; i < 4; ++i)
{
money_2 += money_2 * 0.0175; //加上一年的利息,单利计息
}
printf("%.2lf %.2lf", money_1,money_2);
return 0;
}
B题 判断闰年
方法一
本题主要考察if判断,要掌握闰年的条件。
闰年条件:
- 能被4整除但不能被100整除
- 能被400整除
C语言
#include <stdio.h>
int main()
{
int year, mon, day;
scanf("%d-%d-%d", &year, &mon, &day);
if(year % 400 == 0 || year % 4 == 0 && year % 100 != 0) //闰年条件
{
printf("%s", "yes");
}
else
{
printf("%s", "no");
}
return 0;
}
C题 acb模式
题目来源:132-pattern
前言
由于本题中
n
n
n 的最大值可以到
1
0
4
10^4
104
,因此对于一个满足
a
c
b
acb
acb 模式的三元组下标
(
i
,
j
,
k
)
(i, j, k)
(i,j,k),枚举其中的 2 个下标时间复杂度为
O
(
n
2
)
O(n^2)
O(n2)
,很容易超出时间限制。
因此我们可以考虑枚举其中的 1 1 1 个下标,并使用合适的数据结构维护另外的 2 2 2 个下标的可能值。
方法一 枚举 c
枚举 c c c 是容易想到并且也是最容易实现的。由于 c c c 是模式中的最大值,并且其出现在 a a a 和 b b b 的中间,因此我们只需要从左到右枚举 c c c 的下标 j j j,那么:
由于 a a a 是模式中的最小值,因此我们在枚举 j j j 的同时,维护数组 a 中左侧元素 a [ 0.. j − 1 ] a[0..j-1] a[0..j−1] 的最小值,即为 a a a 对应的元素 a [ i ] a[i] a[i]。需要注意的是,只有 a [ i ] < a [ j ] a[i] < a[j] a[i]<a[j] 时, a [ i ] a[i] a[i] 才能作为 a 对应的元素;
由于 b b b 是模式中的次小值,因此我们可以使用一个有序集合(例如平衡树)维护数组 a a a 中右侧元素 a [ j + 1.. n − 1 ] a[j+1..n-1] a[j+1..n−1] 中的所有值。当我们确定了 a [ i ] a[i] a[i] 和 a [ j ] a[j] a[j] 之后,只需要在有序集合中查询严格比 a [ i ] a[i] a[i] 大的那个最小的元素,即为 a [ k ] a[k] a[k]。需要注意的是,只有 $a[k] < a[j] 时 , 时, 时,a[k]$ 才能作为 c c c 对应的元素。
C++
#include<iostream>
#include <set>
#include <vector>
using namespace std;
class Solution {
public:
bool find132pattern(vector<int>& nums) {
int n = nums.size();
if (n < 3) {
return false;
}
// 左侧最小值
int left_min = nums[0];
// 右侧所有元素
multiset<int> right_all;
for (int k = 2; k < n; ++k) {
right_all.insert(nums[k]);
}
for (int j = 1; j < n - 1; ++j) {
if (left_min < nums[j]) {
auto it = right_all.upper_bound(left_min);
if (it != right_all.end() && *it < nums[j]) {
return true;
}
}
left_min = min(left_min, nums[j]);
right_all.erase(right_all.find(nums[j + 1]));
}
return false;
}
};
int main()
{
Solution sol;
int n;
cin >> n;
vector<int> array(n);
for (int i = 0; i < n; ++i){
cin >> array[i];
}
bool res = sol.find132pattern(array);
if(res){
cout << "True";
}
else{
cout << "False";
}
return 0;
}
Java
import java.io.*;
import java.util.*;
import java.util.TreeMap;
class Solution {
public boolean find132pattern(int[] nums) {
// a < c < b
int n = nums.length;
if (n < 3) return false;
TreeMap<Integer, Integer> rightNums = new TreeMap<>();//储存当前位置右边的 <数值,个数> c
int leftMin = nums[0]; // 左侧最小值 a
for (int i = 2; i < n; i++) {
rightNums.put(nums[i], rightNums.getOrDefault(nums[i], 0) + 1);
}
for (int i = 1; i < n - 1; i++) {
//检查
if (leftMin < nums[i]) { // a<b
Integer c = rightNums.ceilingKey(leftMin + 1); //获得比a大的最小元素 c>=a+1
if (c != null && c < nums[i]) { //c<b
return true; //符合情况
}
}
//维护结构
rightNums.put(nums[i + 1], rightNums.get(nums[i + 1]) - 1);
if (rightNums.get(nums[i + 1]) == 0) rightNums.remove(nums[i + 1]);
leftMin = Math.min(leftMin, nums[i]);
}
return false;
}
}
public class Main {
public static void main(String args[]) throws Exception {
Scanner cin=new Scanner(System.in);
int n = cin.nextInt();
int[] arr = new int[n];
for(int i =0;i<n;++i){
arr[i]=cin.nextInt();
}
Solution sol = new Solution();
if(sol.find132pattern(arr)){
System.out.print("True");
}else{
System.out.print("False");
}
}
}
方法二 枚举a
如果我们从左到右枚举 a a a 的下标 i i i,那么 j , k j, k j,k 的下标范围都是减少的,这样就不利于对它们进行维护。因此我们可以考虑从右到左枚举 i i i。
那么我们应该如何维护 j , k j, k j,k 呢?在 a c b acb acb 模式中,如果 a < b a<b a<b 并且 b < c b<c b<c,那么根据传递性, a < c a<c a<c 也是成立的,那么我们可以使用下面的方法进行维护:
-
我们使用一种数据结构维护所有遍历过的元素,它们作为 b b b 的候选元素。每当我们遍历到一个新的元素时,就将其加入数据结构中;
-
在遍历到一个新的元素的同时,我们可以考虑其是否可以作为 c c c。如果它作为 c c c,那么数据结构中所有严格小于它的元素都可以作为 b b b,我们将这些元素全部从数据结构中移除,并且使用一个变量维护所有被移除的元素的最大值。这些被移除的元素都是可以真正作为 b b b 的,并且元素的值越大,那么我们之后找到 a a a 的机会也就越大。
那么这个「数据结构」是什么样的数据结构呢?我们尝试提取出它进行的操作:
-
它需要支持添加一个元素;
-
它需要支持移除所有严格小于给定阈值的所有元素;
-
上面两步操作是「依次进行」的,即我们先用给定的阈值移除元素,再将该阈值加入数据结构中。
这就是「单调栈」。在单调栈中,从栈底到栈顶的元素是严格单调递减的。当给定阈值 x x x 时,我们只需要不断地弹出栈顶的元素,直到栈为空或者 x x x 严格小于栈顶元素。此时我们再将 x x x 入栈,这样就维护了栈的单调性。
因此,我们可以使用单调栈作为维护 b b b 的数据结构,并给出下面的算法:
-
我们用单调栈维护所有可以作为 b b b 的候选元素。初始时,单调栈中只有唯一的元素 a [ n − 1 ] \textit{a}[n-1] a[n−1]。我们还需要使用一个变量 max_k \textit{max\_k} max_k 记录所有可以真正作为 b b b 的元素的最大值;
-
随后我们从 n − 2 n-2 n−2 开始从右到左枚举元素 a [ i ] a[i] a[i]:
-
首先我们判断 a [ i ] a[i] a[i] 是否可以作为 a a a。如果 a [ i ] < max_k a[i] < \textit{max\_k} a[i]<max_k,那么它就可以作为 a a a,我们就找到了一组满足 a c b acb acb 模式的三元组;
-
随后我们判断 a [ i ] a[i] a[i] 是否可以作为 c c c,以此找出哪些可以真正作为 b b b 的元素。我们将 a [ i ] a[i] a[i] 不断地与单调栈栈顶的元素进行比较,如果 a [ i ] a[i] a[i] 较大,那么栈顶元素可以真正作为 b b b,将其弹出并更新 max_k \textit{max\_k} max_k;
-
最后我们将 a [ i ] a[i] a[i] 作为 b b b 的候选元素放入单调栈中。这里可以进行一个优化,即如果 a [ i ] ≤ max_k a[i] \leq \textit{max\_k} a[i]≤max_k,那么我们也没有必要将 a [ i ] a[i] a[i] 放入栈中,因为即使它在未来被弹出,也不会将 max_k \textit{max\_k} max_k 更新为更大的值。
-
-
在枚举完所有的元素后,如果仍未找到满足 acb 模式的三元组,那就说明其不存在。
C语言
#include<stdio.h>
#define bool int
#define false 0
#define true 1
bool find132pattern(int* nums, int numsSize) {
int n = numsSize;
int candidate_k[n], top = 0;
candidate_k[top++] = nums[n - 1];
int max_k = INT_MIN;
for (int i = n - 2; i >= 0; --i) {
if (nums[i] < max_k) {
return true;
}
while (top && nums[i] > candidate_k[top - 1]) {
max_k = candidate_k[--top];
}
if (nums[i] > max_k) {
candidate_k[top++] = nums[i];
}
}
return false;
}
int main()
{
int n;
scanf("%d",&n);
int array[10000000];
for(int i=0; i<n; ++i){
scanf("%d",array+i);
}
bool ans = find132pattern(array,n);
if(ans) printf("True");
else printf("False");
return 0;
}
C++
#include<vector>
#include<iostream>
class Solution {
public:
bool find132pattern(vector<int>& nums) {
int n = nums.size();
stack<int> candidate_k;
candidate_k.push(nums[n - 1]);
int max_k = INT_MIN;
for (int i = n - 2; i >= 0; --i) {
if (nums[i] < max_k) {
return true;
}
while (!candidate_k.empty() && nums[i] > candidate_k.top()) {
max_k = candidate_k.top();
candidate_k.pop();
}
if (nums[i] > max_k) {
candidate_k.push(nums[i]);
}
}
return false;
}
};
int main()
{
Solution sol;
int n;
cin >> n;
vector<int> array(n);
for (int i = 0; i < n; ++i){
cin >> array[i];
}
bool res = sol.find132pattern(array);
if(res){
cout << "True";
}
else{
cout << "False";
}
return 0;
}
Java
import java.io.*;
import java.util.*;
import java.util.TreeMap;
class Solution {
public boolean find132pattern(int[] nums) {
int n = nums.length;
Deque<Integer> candidateK = new LinkedList<Integer>();
candidateK.push(nums[n - 1]);
int maxK = Integer.MIN_VALUE;
for (int i = n - 2; i >= 0; --i) {
if (nums[i] < maxK) {
return true;
}
while (!candidateK.isEmpty() && nums[i] > candidateK.peek()) {
maxK = candidateK.pop();
}
if (nums[i] > maxK) {
candidateK.push(nums[i]);
}
}
return false;
}
}
public class Main {
public static void main(String args[]) throws Exception {
Scanner cin=new Scanner(System.in);
int n = cin.nextInt();
int[] arr = new int[n];
for(int i =0;i<n;++i){
arr[i]=cin.nextInt();
}
Solution sol = new Solution();
if(sol.find132pattern(arr)){
System.out.print("True");
}else{
System.out.print("False");
}
}
}
D题 方形星系
题目来源:spiral-matrix-ii
方法一:模拟
模拟矩阵的生成。按照要求,初始位置设为矩阵的左上角,初始方向设为向右。若下一步的位置超出矩阵边界,或者是之前访问过的位置,则顺时针旋转,进入下一个方向。如此反复直至填入
n
2
n^2
n2
个元素。
记 matrix \textit{matrix} matrix 为生成的矩阵,其初始元素设为 0 0 0。由于填入的元素均为正数,我们可以判断当前位置的元素值,若不为 0 0 0,则说明已经访问过此位置。
C语言
#include<stdio.h>
int** generateMatrix(int n, int* returnSize, int** returnColumnSizes) {
int maxNum = n * n;
int curNum = 1;
int** matrix = malloc(sizeof(int*) * n);
*returnSize = n;
*returnColumnSizes = malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) {
matrix[i] = malloc(sizeof(int) * n);
memset(matrix[i], 0, sizeof(int) * n);
(*returnColumnSizes)[i] = n;
}
int row = 0, column = 0;
int directions[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 右下左上
int directionIndex = 0;
while (curNum <= maxNum) {
matrix[row][column] = curNum;
curNum++;
int nextRow = row + directions[directionIndex][0], nextColumn = column + directions[directionIndex][1];
if (nextRow < 0 || nextRow >= n || nextColumn < 0 || nextColumn >= n || matrix[nextRow][nextColumn] != 0) {
directionIndex = (directionIndex + 1) % 4; // 顺时针旋转至下一个方向
}
row = row + directions[directionIndex][0];
column = column + directions[directionIndex][1];
}
return matrix;
}
int main(){
int n;
scanf("%d",&n);
int size,columnSizes;
int** matrix = generateMatrix(m,&size,&columnSizes);
for(int i=0;i<size;++i){
for(int j=0;j<columnSizes;++j){
if(j>0) printf(" ");
printf("%d",matrix[i][j]);
}
printf("\n");
}
return 0;
}
C++
#include<vector>
#include<iostream>
using namespace std;
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
int maxNum = n * n;
int curNum = 1;
vector<vector<int>> matrix(n, vector<int>(n));
int row = 0, column = 0;
vector<vector<int>> directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 右下左上
int directionIndex = 0;
while (curNum <= maxNum) {
matrix[row][column] = curNum;
curNum++;
int nextRow = row + directions[directionIndex][0], nextColumn = column + directions[directionIndex][1];
if (nextRow < 0 || nextRow >= n || nextColumn < 0 || nextColumn >= n || matrix[nextRow][nextColumn] != 0) {
directionIndex = (directionIndex + 1) % 4; // 顺时针旋转至下一个方向
}
row = row + directions[directionIndex][0];
column = column + directions[directionIndex][1];
}
return matrix;
}
};
int main()
{
int n;
cin>>n;
Solution sol;
vector<vector<int>> matrix = sol.generateMatrix(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if(j>0) cout<<" ";
cout<<matrix[i][j];
}
cout<<endl;
}
return 0;
}
Java
import java.util.Scanner;
class Solution {
public int[][] generateMatrix(int n) {
int[][] matrix = new int[n][n];
int index = 1;
int row = 0, col = 0;
final int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
int directionIndex = 0;
while (index <= n * n) {
matrix[row][col] = index;
int newRow = row + directions[directionIndex][0];
int newCol = col + directions[directionIndex][1];
if (newRow < 0 || newRow >= n || newCol < 0 || newCol >= n || matrix[newRow][newCol] != 0) {
++directionIndex;
directionIndex %= 4;
}
row += directions[directionIndex][0];
col += directions[directionIndex][1];
++index;
}
return matrix;
}
}
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Solution solution = new Solution();
int n = in.nextInt();
int[][] matrix = solution.generateMatrix(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if(j>0) System.out.print(" ");
System.out.print(matrix[i][j]);
}
System.out.print("\n");
}
}
}
方法二:按层模拟
可以将矩阵看成若干层,首先填入矩阵最外层的元素,其次填入矩阵次外层的元素,直到填入矩阵最内层的元素。
定义矩阵的第 kk 层是到最近边界距离为 kk 的所有顶点。例如,下图矩阵最外层元素都是第 11 层,次外层元素都是第 22 层,最内层元素都是第 33 层。
[[1, 1, 1, 1, 1, 1],
[1, 2, 2, 2, 2, 1],
[1, 2, 3, 3, 2, 1],
[1, 2, 3, 3, 2, 1],
[1, 2, 2, 2, 2, 1],
[1, 1, 1, 1, 1, 1]]
对于每层,从左上方开始以顺时针的顺序填入所有元素。假设当前层的左上角位于
(
top
,
left
)
(\textit{top}, \textit{left})
(top,left),右下角位于
(
bottom
,
right
)
(\textit{bottom}, \textit{right})
(bottom,right),按照如下顺序填入当前层的元素。
从左到右填入上侧元素,依次为 ( top , left ) (\textit{top}, \textit{left}) (top,left) 到 ( top , right ) (\textit{top}, \textit{right}) (top,right)。
从上到下填入右侧元素,依次为 ( top + 1 , right ) (\textit{top} + 1, \textit{right}) (top+1,right) 到 ( bottom , right ) (\textit{bottom}, \textit{right}) (bottom,right)。
如果 left < right \textit{left} < \textit{right} left<right 且 top < bottom \textit{top} < \textit{bottom} top<bottom,则从右到左填入下侧元素,依次为 ( bottom , right − 1 ) (\textit{bottom}, \textit{right} - 1) (bottom,right−1) 到 ( bottom , left + 1 ) (\textit{bottom}, \textit{left} + 1) (bottom,left+1),以及从下到上填入左侧元素,依次为 ( bottom , left ) (\textit{bottom}, \textit{left}) (bottom,left) 到 ( top + 1 , left ) (\textit{top} + 1, \textit{left}) (top+1,left)。
填完当前层的元素之后,将 left \textit{left} left 和 top \textit{top} top 分别增加 1 1 1,将 right \textit{right} right 和 bottom \textit{bottom} bottom 分别减少 1 1 1,进入下一层继续填入元素,直到填完所有元素为止。
C语言
#include<stdio.h>
int** generateMatrix(int n, int* returnSize, int** returnColumnSizes) {
int num = 1;
int** matrix = malloc(sizeof(int*) * n);
*returnSize = n;
*returnColumnSizes = malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) {
matrix[i] = malloc(sizeof(int) * n);
memset(matrix[i], 0, sizeof(int) * n);
(*returnColumnSizes)[i] = n;
}
int left = 0, right = n - 1, top = 0, bottom = n - 1;
while (left <= right && top <= bottom) {
for (int column = left; column <= right; column++) {
matrix[top][column] = num;
num++;
}
for (int row = top + 1; row <= bottom; row++) {
matrix[row][right] = num;
num++;
}
if (left < right && top < bottom) {
for (int column = right - 1; column > left; column--) {
matrix[bottom][column] = num;
num++;
}
for (int row = bottom; row > top; row--) {
matrix[row][left] = num;
num++;
}
}
left++;
right--;
top++;
bottom--;
}
return matrix;
}
int main(){
int n;
scanf("%d",&n);
int size,columnSizes;
int** matrix = generateMatrix(m,&size,&columnSizes);
for(int i=0;i<size;++i){
for(int j=0;j<columnSizes;++j){
if(j>0) printf(" ");
printf("%d",matrix[i][j]);
}
printf("\n");
}
return 0;
}
C++
#include<vector>
#include<iostream>
using namespace std;
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
int num = 1;
vector<vector<int>> matrix(n, vector<int>(n));
int left = 0, right = n - 1, top = 0, bottom = n - 1;
while (left <= right && top <= bottom) {
for (int column = left; column <= right; column++) {
matrix[top][column] = num;
num++;
}
for (int row = top + 1; row <= bottom; row++) {
matrix[row][right] = num;
num++;
}
if (left < right && top < bottom) {
for (int column = right - 1; column > left; column--) {
matrix[bottom][column] = num;
num++;
}
for (int row = bottom; row > top; row--) {
matrix[row][left] = num;
num++;
}
}
left++;
right--;
top++;
bottom--;
}
return matrix;
}
};
int main()
{
int n;
cin>>n;
Solution sol;
vector<vector<int>> matrix = sol.generateMatrix(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if(j>0) cout<<" ";
cout<<matrix[i][j];
}
cout<<endl;
}
return 0;
}
Java
import java.util.Scanner;
class Solution {
public int[][] generateMatrix(int n) {
int num = 1;
int[][] matrix = new int[n][n];
int left = 0, right = n - 1, top = 0, bottom = n - 1;
while (left <= right && top <= bottom) {
for (int column = left; column <= right; column++) {
matrix[top][column] = num;
num++;
}
for (int row = top + 1; row <= bottom; row++) {
matrix[row][right] = num;
num++;
}
if (left < right && top < bottom) {
for (int column = right - 1; column > left; column--) {
matrix[bottom][column] = num;
num++;
}
for (int row = bottom; row > top; row--) {
matrix[row][left] = num;
num++;
}
}
left++;
right--;
top++;
bottom--;
}
return matrix;
}
}
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Solution solution = new Solution();
int n = in.nextInt();
int[][] matrix = solution.generateMatrix(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if(j>0) System.out.print(" ");
System.out.print(matrix[i][j]);
}
System.out.print("\n");
}
}
}
E题 乾坤挪移
方法一 假装移动数组
每次输出数组时,都从第 i i i 位输出,需要输出 n n n 个元素,可以利用取模运算符获得正确的下标
C语言
#include <stdio.h>
#include <malloc.h>
int main()
{
int n;
scanf("%d", &n);
int* array = (int*)malloc(sizeof(int) * n); //动态创建一个n个元素的数组
for (int i = 0; i < n; ++i)
{
scanf("%d", array + i);
}
for (int i = 0; i < n; ++i)
{
for (int j = i; j < i+n; ++j)
{
if (j > i) printf(" ");
printf("%d", array[j % n]);
}
printf("\n");
}
free(array); //释放array
array = NULL;
return 0;
}
C++
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n;
cin >> n;
vector<int> array(n);
for (int i = 0; i < n; ++i)
{
cin >> array[i];
}
for (int i = 0; i < n; ++i)
{
for (int j = i; j < i+n; ++j)
{
if (j > i) cout << " ";
cout << array[j % n];
}
cout << endl;
}
return 0;
}
Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n;
n = in.nextInt();
int[] array = new int[n];
for (int i = 0; i < n; i++) {
array[i] = in.nextInt();
}
for (int i = 0; i < n; i++) {
for (int j = i; j < i + n; j++) {
if (j > i) System.out.print(" ");
System.out.print(array[j % n]);
}
System.out.print("\n");
}
}
}
F题 下一个更小元素
方法一:单调栈 + 循环数组
我们可以使用单调栈解决本题。单调栈中保存的是下标,从栈底到栈顶的下标在数组 nums \textit{nums} nums 中对应的值是单调不升的。
每次我们移动到数组中的一个新的位置 i i i,我们就将当前单调栈中所有对应值小于 nums [ i ] \textit{nums}[i] nums[i] 的下标弹出单调栈,这些值的下一个更大元素即为 nums [ i ] \textit{nums}[i] nums[i](证明很简单:如果有更靠前的更大元素,那么这些位置将被提前弹出栈)。随后我们将位置 i i i 入栈。
但是注意到只遍历一次序列是不够的,例如序列 [ 2 , 3 , 1 ] [2,3,1] [2,3,1],最后单调栈中将剩余 [ 3 , 1 ] [3,1] [3,1],其中元素 [ 1 ] [1] [1] 的下一个更大元素还是不知道的。
一个朴素的思想是,我们可以把这个循环数组「拉直」,即复制该序列的前 n − 1 n-1 n−1 个元素拼接在原序列的后面。这样我们就可以将这个新序列当作普通序列,用上文的方法来处理。
而在本题中,我们不需要显性地将该循环数组「拉直」,而只需要在处理时对下标取模即可。
C语言
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int* nextGreaterElements(int* nums, int numsSize, int* returnSize) {
*returnSize = numsSize;
if (numsSize == 0) {
return NULL;
}
int* ret = malloc(sizeof(int) * numsSize);
memset(ret, -1, sizeof(int) * numsSize);
int stk[numsSize * 2 - 1], top = 0;
for (int i = 0; i < numsSize * 2 - 1; i++) {
while (top > 0 && nums[stk[top - 1]] > nums[i % numsSize]) {
ret[stk[top - 1]] = nums[i % numsSize];
top--;
}
stk[top++] = i % numsSize;
}
return ret;
}
int main()
{
int n;
scanf("%d", &n);
int* array = malloc(sizeof(int) * n);
for (int i = 0; i < n; ++i)
{
scanf("%d", array+i);
}
int len;
int* ans = nextGreaterElements(array, n, &len);
for (int i = 0; i < n; ++i)
{
if (i > 0) printf(" ");
printf("%d", ans[i]);
}
return 0;
}
C++
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
int n = nums.size();
vector<int> ret(n, -1);
stack<int> stk;
for (int i = 0; i < n * 2 - 1; i++) {
while (!stk.empty() && nums[stk.top()] > nums[i % n]) {
ret[stk.top()] = nums[i % n];
stk.pop();
}
stk.push(i % n);
}
return ret;
}
};
int main()
{
int n;
cin >> n;
Solution sol;
vector<int> array(n);
for (int i = 0; i < n; ++i)
{
cin >> array[i];
}
auto ans = sol.nextGreaterElements(array);
for (int i = 0; i < ans.size(); ++i)
{
if (i > 0) cout << " ";
cout << ans[i];
}
return 0;
}
Java
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Scanner;
class Solution {
public int[] nextGreaterElements(int[] nums) {
int n = nums.length;
int[] ret = new int[n];
Arrays.fill(ret, -1);
Deque<Integer> stack = new LinkedList<Integer>();
for (int i = 0; i < n * 2 - 1; i++) {
while (!stack.isEmpty() && nums[stack.peek()] > nums[i % n]) {
ret[stack.pop()] = nums[i % n];
}
stack.push(i % n);
}
return ret;
}
}
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] array = new int[n];
for (int i = 0; i < n; i++) {
array[i] = in.nextInt();
}
Solution sol = new Solution();
int[] ans = sol.nextGreaterElements(array);
for (int i = 0; i < n; i++) {
if (i > 0) System.out.print(" ");
System.out.print(array[i]);
}
}
}
G题 求解高次方程
方法一:二分查找
通过求导可得该函数在
[
20
,
50
]
[20,50]
[20,50] 上是单调递增函数,则设
f
(
x
0
)
=
0
f(x_0)=0
f(x0)=0,有
x
<
x
0
,
f
(
x
)
<
f
(
x
0
)
x<x_0, f(x)<f(x_0)
x<x0,f(x)<f(x0)或
x
>
x
0
,
f
(
x
)
>
f
(
x
0
)
x>x_0, f(x)>f(x_0)
x>x0,f(x)>f(x0),函数图像如图
可得在这一区间内,函数值是从小到大有序的,可以使用二分查找找到特定值
C
#include <stdio.h>
#include <math.h>
inline double f(const double x)
{
// f(x)=x^4+70*x^3-4175*x^2+15750*x-275625;
return pow(x, 4) + 70 * pow(x, 3) - 4175 * pow(x, 2) + 15750 * x - 275625;
}
double binarySearch(double left, double right)
{
int i = 1;
const double delta = 0.000000000001;
double mid;
while (left < right)
{
mid = (left + right) / 2;
double val = f(mid);
//cout <<i <<" "<< "f(" << mid << ")= " << val << endl;
if (-delta <= val && val <= delta)
{
return mid;
}
else if (val < -delta)
{
left = mid + delta;
}
else
{
right = mid - delta;
}
++i;
}
return mid;
}
int main()
{
double ans = binarySearch(20.0, 50.0);
printf("%.6lf", ans);
return 0;
}
C++
#include <iostream>
#include <math.h>
#include <iomanip>
using namespace std;
inline double f(double x){
// f(x)=x^4+70*x^3-4175*x^2+15750*x-275625;
return pow(x, 4) + 70 * pow(x, 3) - 4175 * pow(x, 2) + 15750 * x - 275625;
}
double binarySearch(double left, double right){
int i = 1;
double delta = 0.000000000001;
double mid;
while (left<right){
mid = (left + right) / 2;
double val = f(mid);
//cout <<i <<" "<< "f(" << mid << ")= " << val << endl;
if(-delta <= val && val <= delta){
return mid;
}
else if(val<-delta){
left = mid + delta;
}
else{
right = mid - delta;
}
++i;
}
return mid;
}
int main(){
double ans = binarySearch(20.0, 50.0);
//格式控制 fixed 小数表示,setprecision(n)保留n位小数
cout << setiosflags(ios::fixed) << setprecision(6) << ans;
return 0;
}
H题 存在重复元素
题目来源:contains-duplicate
方法一:排序
在对数字从小到大排序之后,数组的重复元素一定出现在相邻位置中。因此,我们可以扫描已排序的数组,每次判断相邻的两个元素是否相等,如果相等则说明存在重复的元素。
但是时间复杂度为
n
log
(
n
)
n\log(n)
nlog(n),会超时。
C
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#define scanf scanf_s
int cmp(const void* _a, const void* _b) {
int a = *(int*)_a, b = *(int*)_b;
return a - b;
}
bool containsDuplicate(int* nums, int numsSize) {
qsort(nums, numsSize, sizeof(int), cmp);
for (int i = 0; i < numsSize - 1; i++) {
if (nums[i] == nums[i + 1]) {
return true;
}
}
return false;
}
int main()
{
int n;
scanf("%d", &n);
int* array = malloc(sizeof(int) * n);
for (int i = 0; i < n; ++i)
{
scanf("%d", array + i);
}
if (containsDuplicate(array, n))
printf("true");
else
printf("false");
free(array);
return 0;
}
C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
sort(nums.begin(), nums.end());
int n = nums.size();
for (int i = 0; i < n - 1; i++) {
if (nums[i] == nums[i + 1]) {
return true;
}
}
return false;
}
};
int main()
{
int n;
cin >> n;
vector<int> array(n);
for (int i = 0; i < n; ++i)
{
cin >> array[i];
}
Solution sol;
if (sol.containsDuplicate(array)) cout << "true";
else cout << "false";
return 0;
}
Java
import java.util.Arrays;
import java.util.Scanner;
class Solution {
public boolean containsDuplicate(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
for (int i = 0; i < n - 1; i++) {
if (nums[i] == nums[i + 1]) {
return true;
}
}
return false;
}
}
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] array = new int[n];
for (int i = 0; i < n; i++) {
array[i] = in.nextInt();
}
Solution sol = new Solution();
if(sol.containsDuplicate(array)) System.out.print("true");
else System.out.print("false");
}
}
方法二:哈希表
对于数组中每个元素,我们将它插入到哈希表中。如果插入一个元素时发现该元素已经存在于哈希表中,则说明存在重复的元素。
C++
#include<iostream>
#include<vector>
#include<set>
#include<unordered_set>
using namespace std;
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
//使用stl的set
unordered_set<int> hash;
for (auto& elem : nums){
auto res = hash.insert(elem);
if (!res.second) return true;
}
return false;
}
};
int main() {
int n;
cin >> n;
vector<int> vect(n);
for (int i = 0; i < n; ++i) {
scanf("%d", &vect[i]);
//cin >> vect[i];
}
Solution sol;
if (sol.containsDuplicate(vect)) {
cout << "true";
}
else {
cout << "false";
}
return 0;
}
Java
import java.util.*;
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<Integer>();
for (int x : nums) {
if (!set.add(x)) {
return true;
}
}
return false;
}
}
public class Main{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] array = new int[n];
for(int i=0;i<n;++i){
array[i]=in.nextInt();
}
Solution sol = new Solution();
if(sol.containsDuplicate(array)) System.out.print("true");
else System.out.print("false");
}
}