个人觉得,对于计算机专业的大学生来说,算法竞赛应该是性价比最高的比赛了。除了icpc和ccpc这两个比较难拿国奖之外,其他的比赛获奖难度并不大,比如蓝桥杯、天梯赛、睿抗,认真学习一年算法,水个国奖完全没问题。
本篇博客是我在一年多的学习和比赛中所做的笔记,记录的内容都是我认为在比赛中高频次出现的算法,而且除了线段树之外都是比较基础的算法。
应该会不断更新吧。
转换方法很简单,用例子来说明:
总而言之就是把小数拆成两部分:非循环部分和循环部分。非循环部分除以10的n次幂得到一个分数,循环部分除以999…和10的n次幂的积,得到一个分数。两个分数加起来,通分,就得到了最后的结果。
import java.util.List;
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
public class Main{
static Scanner sc = new Scanner(System.in);
static int p, q;
static Integer[] arr = new Integer[1000010];
static double EPS = 1e-8 * 0.35;
static long gcd(long a, long b) {
if(b == 0) {
return a;
}
return gcd(b, a % b);
}
public static void main(String[] args) {
p = sc.nextInt();
q = sc.nextInt();
String s = sc.next();
long x1 = p == 1 ? 0 : Long.valueOf(s.substring(0, p - 1));
long y1 = 1;
for(int i = 1; i < p; i++) {
y1 *= 10;
}
long x2 = Long.valueOf(s.substring(p - 1));
long y2 = 9;
for(int i = p; i < q; i++) {
y2 = y2 * 10 + 9;
}
for(int i = 1; i < p; i++) {
y2 *= 10;
}
// System.out.println(x1 + " " + y1);
// System.out.println(x2 + " " + y2);
long x = x1 * y2 + x2 * y1;
long y = y1 * y2;
long g = gcd(x, y);
System.out.println(x / g + " " + y / g);
}
}
一个数A可以被分解成如下若干个质因数乘积的形式,pi为质因数:
获取质因数p和它们的指数,返回值map的key是质因数,value是该质因数的指数:
map<int, int> getYue(int a){
map<int, int> res;
for(int i = 2; i <= a / i; i++){
if(a % i == 0){
int cnt = 0;
while(a % i == 0){
cnt++;
a /= i;
}
res[i] = cnt;
}
}
if(a != 1){
res[a] = 1;
}
return res;
}
最大公约数
int gcd(int a, int b)
{
if (a % b==0) return b;
else return gcd(b, a % b);
}
问[1, n]有多少个素数
#include
using namespace std;
bool isPrime[1000010];
int n;
int ans;
int main()
{
cin >> n;
for(int i = 2; i <= n; i++)
{
isPrime[i] = true;
}
for(int i = 2; i <= n; i++)
{
if(isPrime[i])
{
ans++;
for(int j = 2; j * i <= n; j++)
{
isPrime[j * i] = false;
}
}
}
cout << ans << endl;
}
互质的定义:公约数只有1的两个整数,叫做互质整数。
phi(n)的含义是{1, 2, 3 …, n-1, n}中与n的互质的数的个数,它的计算公式为:
phi(n) = n * (1 - 1/p1) * (1 - 1/p2) * (1 - 1/p3) * (1 - 1/p4) * …* (1 - 1/pn);
其中p1,p2,p3…pn是n的质因子
计算一个数的欧拉函数的代码如下:
int getPhi(int x){
// 获取质因数,p是质因数列表
vector<int> p;
int tmp = x;
for(int i = 2; i <= tmp / i; i++){
if(tmp % i == 0){
p.push_back(i);
while(tmp % i == 0){
tmp /= i;
}
}
}
if(tmp != 1){
p.push_back(tmp);
}
// 根据质因数列表,计算欧拉函数。
// 当计算n * (1 - 1 / pi)时,要写成n - n / pi的形式
int res = x;
for(auto i : p){
res = res - res / i;
}
return res;
}
int p[N];
for (int i = 1; i <= n; i ++ ) p[i] = i;
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
返回 a ^ b mod p
ll qmi(ll a, ll b, ll p)
{
ll ans = 1;
while(b > 0)
{
if(b & 1 == 1)
{
ans = ans * a % p;
}
a = a * a % p;
b = b >> 1;
}
return ans;
}
从y个元素里面取x个元素有C[y][x]种取法。
如果y = x或x = 0,那么C[y][x] = 1;如果x > y,那么C[y][x] = 0
它可以被划分为两种情况,取第y个元素C[y - 1][x - 1]和不取第y个元素C[y - 1][x]。
所以C[y][x] = C[y - 1][x - 1] + C[y - 1][x]。
int c[N][N];
void init()
{
for (int i = 0; i < N; i ++ )
for (int j = 0; j <= i; j ++ )
if (!j) c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
#include
using namespace std;
const int M = 200010; // 序列的长度
struct Node{
int l, r;
int v;
}bt[M * 4]; // 开四倍的线段树数组
int m, p;
void build(int u, int l, int r){
bt[u].l = l;
bt[u].r = r;
int mid = (l + r) / 2; // 最好把mid写出来,容易出错
if(l < r){
build(u * 2, l, mid);
build(u * 2 + 1, mid + 1, r);
}
}
// 根据子节点的状态计算u节点
void pushUp(int u){
bt[u].v = max(bt[u * 2].v, bt[u * 2 + 1].v);
}
// 把序列中第x个数修改为v,是从树根往下递归,回溯时pushUp
void modify(int u, int x, int v){
if(bt[u].l == bt[u].r && bt[u].l == x){
bt[u].v = v;
return ;
}
int mid = (bt[u].l + bt[u].r) / 2;
if(x <= mid){
modify(u * 2, x, v);
}
else {
modify(u * 2 + 1, x, v);
}
pushUp(u);
}
// 查询[l, r]区间的最大值
int query(int u, int l, int r){
// 查询区间包含了整棵树
if(bt[u].l >= l && bt[u].r <= r){
return bt[u].v;
}
// 如果与查询区间左子树有交集,则递归左子树,与右子树有交集则递归右子树
// 不存在查询区间与整棵树无交集的情况
int mid = (bt[u].l + bt[u].r) / 2;
int res = 0;
if(l <= mid){
res = query(u * 2, l, r);
}
if(r > mid){
res = max(res, query(u * 2 + 1, l, r));
}
return res;
}
int main(){
build(1, 1, M);
cin >> m >> p;
int len = 0, a = 0; // len是序列的长度
while(m--){
string s;
int x;
cin >> s >> x;
if(s == "A"){
int v = ((long long)x + (long long) a) % p; // x + a可能爆int
modify(1, ++len, v);
}
else{
a = query(1, len - x + 1, len);
cout << a << endl;
}
}
}
#include
using namespace std;
// add表示当前节点包含区间内所有元素都要增加的值,也就是懒标记
// 该节点的值是计算过懒标记后的值,在本题中的意思就是,该节点的sum值,已经加上了该节点的add值
struct Node{
int l, r;
long long sum, add;
}bt[400010];
int n, m;
int initValue[100010];
void pushUp(int u){
bt[u].sum = bt[u * 2].sum + bt[u * 2 + 1].sum;
}
// pushDonw操作把当前节点的add传递给子节点
void pushDown(int u){
// 把当前节点懒标记add清空,节点的值sum不变
int add = bt[u].add;
bt[u].add = 0;
// 子节点加上懒标记add,并更新sum值
Node* ln = bt + u * 2;
Node* rn = bt + u * 2 + 1;
ln->add += add;
rn->add += add;
ln->sum += add * (ln->r - ln->l + 1);
rn->sum += add * (rn->r - rn->l + 1);
}
long long query(int u, int l, int r){
// 如果查询区间包含节点区间,直接返回
if(bt[u].r <= r && bt[u].l >= l){
return bt[u].sum;
}
// 否则,先执行pushDown操作,然后根据情况递归查询左区间和右区间
pushDown(u);
int mid = (bt[u].l + bt[u].r) / 2;
long long res = 0;
if(mid >= l){
res += query(u * 2, l, r);
}
if(mid < r) {
res += query(u * 2 + 1, l, r);
}
return res;
}
void modify(int u, int l, int r, int add){
// 如果修改区间包含节点区间,直接修改add和sum
if(bt[u].l >= l && bt[u].r <= r){
bt[u].add += add;
bt[u].sum += add * (bt[u].r - bt[u].l + 1);
return ;
}
// 否则,先执行pushDown操作,然后根据情况递归修改左区间和右区间,递归完要pushUp
pushDown(u);
int mid = (bt[u].r + bt[u].l) / 2;
if(mid >= l){
modify(u * 2, l, r, add);
}
if(mid < r){
modify(u * 2 + 1, l, r, add);
}
pushUp(u);
}
void buildTree(int u, int l, int r){
bt[u].l = l, bt[u].r = r;
int mid = (l + r) / 2;
if(l == r){
// 赋初始值
bt[u].sum = initValue[l];
}
else{
buildTree(u * 2, l, mid);
buildTree(u * 2 + 1, mid + 1, r);
// 因为在build的过程中赋了初始值,所以每次递归后都要pushUp
pushUp(u);
}
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> initValue[i];
}
buildTree(1, 1, n);
while(m--){
string s;
cin >> s;
if(s == "C"){
int l, r, d;
cin >> l >> r >> d;
modify(1, l, r, d);
}
else if(s == "Q"){
int l, r;
cin >> l >> r;
cout << query(1, l, r) << endl;
}
}
}
void floyd()
{
for (int k = 1; k <= n; k ++ )
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
朴素版,复杂度O(n ^ 2)
void dijkstra()
{
d[1] = 0;
for(int i = 0; i < n; i++)
{
int m = INF;
int x = 0;
for(int j = 1; j <= n; j++)
{
if(!flag[j] && d[j] < m)
{
m = d[j];
x = j;
}
}
flag[x] = true;
for (int j = 1; j <= n; j++ )
{
if(!flag[j])
{
d[j] = min(d[j], d[x] + g[x][j]);
}
}
}
}
堆优化版,建立一个小根堆,每次从小根堆中取出的就是距离最短的点,用该点去更新其余点的距离。复杂度O(mlogn)
// acwing原题
#include
#include
#include
using namespace std;
const int INF = 0x3f3f3f3f;
// 存储点的下标和距离,用来构建队列
struct ND{
int idx;
int dist;
};
bool operator<(ND a, ND b){
return a.dist > b.dist;
}
// 存储点的信息和邻边
struct Node{
int idx;
int dist;
bool isMin;
map<Node*, int> nei;
}nodes[150010];
int n, m;
void add(int x, int y, int z){
if(x == y){
return ;
}
if(nodes[x].nei.count(nodes + y)){
nodes[x].nei[nodes + y] = min(nodes[x].nei[nodes + y], z);
}
else {
nodes[x].nei[nodes + y] = z;
}
}
void dijkstra(){
// 首先往队列中塞入第一个点,并把点的dist设置为0
priority_queue<ND> q;
q.push({1, 0});
nodes[1].dist = 0;
// 和朴素版不太一样,不是用for循环n次,直接用while循环
while(!q.empty()){
ND nd = q.top();
q.pop();
// 如果队头的点已经确定最短距离了,那么continue
if(nodes[nd.idx].isMin){
continue;
}
// 把点的标记设置为true,然后更新这个点的所有相邻点的距离
nodes[nd.idx].isMin = true;
for(pair<Node*, int> j : nodes[nd.idx].nei){
j.first->dist = min(j.first->dist, nodes[nd.idx].dist + j.second);
q.push({j.first->idx, j.first->dist});
}
}
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++){
nodes[i].idx = i;
nodes[i].dist = INF;
}
while(m--){
int x, y, z;
cin >> x >> y >> z;
add(x, y, z);
}
dijkstra();
if(nodes[n].dist == INF){
cout << -1 << endl;
}
else {
cout << nodes[n].dist << endl;
}
}
可以限制经过的边数,如下限制边数为k
static Scanner sc = new Scanner(System.in);
static int n;
static int m, k;
static int[] dist = new int[510];
static final int INF = 0x3f3f3f3f;
static int[] neDist = new int[510];
static List<Edge> edges = new ArrayList<>();
static void bellmanFord() {
for(int i = 1; i <= n; i++) {
dist[i] = INF;
}
dist[1] = 0;
for(int i = 1; i <= k; i++) {
for(int j = 1; j <= n; j++) {
neDist[j] = dist[j];
}
for(Edge edge : edges) {
// 核心就是这一行,更新neDist使用dist+边长
neDist[edge.y] = Math.min(neDist[edge.y], dist[edge.x] + edge.z);
}
for(int j = 1; j <= n; j++) {
dist[j] = neDist[j];
}
}
}
spfa算法可以求带负权边的最短路,也可以判负环,
struct Node{
int idx;
int dist;
int cnt; // 最短路经过的边数
bool inQ;
map<Node*, int> nei;
}nodes[100010];
// s代表源结点下标
bool spfa(){
queue<Node*> q;
q.push(nodes + s);
nodes[s].dist = 0;
nodes[s].inQ = true; // 注意要实时更新结点是否在队列中的状态
while(!q.empty()){
Node* node = q.front();
q.pop();
node->inQ = false;
for(pair<Node*, int> i : node->nei){
if(node->dist + i.second < i.first->dist){
i.first->dist = node->dist + i.second;
i.first->cnt++; // 每次更新最短距离,说明最短路又多经过了一条边
if(i.first->cnt >= n){ // 最短路经过的变数大于等于n,说明有负环
return true;
}
if(!i.first->inQ){
q.push(i.first);
i.first->inQ = true;
}
}
}
}
return false; // 如果没负环,则执行到末尾,所有点的最短路都求出来了
}
初始化所有点到集合的距离为INF,重复以下操作n次:
static int[] dist = new int[510];
static int prim() {
Set<Integer> set = new HashSet<>();
dist[1] = 0;
int ans = 0;
for(int i = 0; i < n; i++) {
int minD = INF;
int minI = 0;
for(int j = 1; j <= n; j++) {
if(minD > dist[j] && !set.contains(j)) {
minI = j;
minD = dist[j];
}
}
if(minD == INF) {
return INF;
}
ans += minD;
set.add(minI);
for(int j = 1; j <= n; j++) {
if(!set.contains(j)) {
// 和dijkstra主要是这一行更新距离的代码不同
dist[j] = Math.min(dist[j], edge[minI][j]);
}
}
}
return ans;
}
// 从左到右,返回第一个大于等于x的数的下标
static int lowerBound(int x, List<Integer> list) {
if(list.get(list.size() - 1) < x) {
return -1;
}
int l = 0, r = list.size() - 1;
while(l < r) {
int mid = (l + r) / 2;
if(list.get(mid) >= x) { // 这里的判断条件,就是要找到的数从左到右第一个满足的条件
r = mid;
}
else {
l = mid + 1;
}
}
return l;
}
// 从右往左,返回第一个小于等于x的数的下标
static int findLastLower(int x, List<Integer> list) {
if(list.get(list.size() - 1) <= x) {
return list.size() - 1;
}
// 二分找到从左往右第一个大于x的数的下标
int l = 0, r = list.size() - 1;
while(l < r) {
int mid = (l + r) / 2;
if(list.get(mid) > x) {
r = mid;
}
else {
l = mid + 1;
}
}
// l - 1就是从右往左第一个小于等于x的数的下标
return l - 1;
}
超级大坑,特别注意
for(auto iter:vec)不改变迭代对象的值,for(auto &iter:vec)可以改变迭代对象的值。
printf直接输出string类型会乱码,要用c_str()方法转换成字符数组再输出
string str = "abc";
printf("%s\n", str); // 错误的
printf("%s\n", str.c_str()); // 正确的
c++字符串的substr方法和其他语言的不太一样,第一个参数是起始下标而第二个参数是字符串长度
string a = "123456789";
cout << a.substr(3, 3) << endl;
cout << a.substr(3) << endl;
输出:
456
456789
c++不可以直接相加数字和字符串,要用to_string方法把数字转为字符串
int num = 1;
string str = to_string(num);
c++ for循环和while循环里定义的变量,不可以通过指针访问,它们会被自动清除
#include
#include
#include
using namespace std;
int main(){
vector<set<int>*> v;
for(int i = 1; i < 5; i++){
set<int> set1;
set1.insert(i);
v.push_back(&set1);
}
for(auto it : v){
cout << it << endl;
}
}
string str;
getline(cin,str);//读入string
char str2[1024];
cin.getline(str2,1024);//读入char数组
c++ stl里已定义了count,所以不要把自己的变量名定义为count
ios::sync_with_stdio(false);
cin.tie(0);
#include
#include
#include
using namespace std;
int main(){
set<string> s;
s.insert("12");
s.insert("99");
auto it = lower_bound(s.begin(), s.end(), "50");
string arr[3] = {"123", "456", "789"};
auto it1 = lower_bound(arr, arr + 3, "3");
cout << *it << endl;
cout << *it1 << endl;
}
更详细的优先队列用法
#include
#include
#include
#include
using namespace std;
struct Student
{
int age;
};
//优先队列比较使用的运算符是 <
bool operator<(const Student s1, const Student s2)
{
return s1.age > s2.age;
//写大于号时,是小根堆
}
int main()
{
//基本数据类型
priority_queue<int> big; //大根堆
priority_queue<int, vector<int>, greater<int>> little; //小根堆
//自定义数据类型
Student s1 = {1}, s2 = {2}, s3 = {-1};
priority_queue<Student> s;
s.push(s1);
s.push(s2);
s.push(s3);
while(!s.empty())
{
cout << s.top().age << endl;
s.pop();
}
}
push() 在队尾插入一个元素
pop() 删除队列第一个元素
size() 返回队列中元素个数
empty() 如果队列空则返回true
front() 返回队列中的第一个元素
back() 返回队列中最后一个元素
set是有序的,默认会把元素按升序排列。
set尽量不要存结构体,因为结构体没有<比较符,而set需要用到<比较符。可以存结构体的指针。
clear(); // 清除所有元素
count(); // 返回某个值元素的个数
empty(); // 如果集合为空,返回true
insert()–在集合中插入元素
erase()–删除集合中的元素,参数为值val或者迭代器
size()–集合中元素的数目
find()–返回一个指向被查找到元素的迭代器
begin(); // 返回指向第一个元素的迭代器
end(); // 返回指向迭代器的最末尾处(即最后一个元素的下一个位置)
for(set<int>::iterator it=numSet.begin(); it!=numSet.end(); it++)
{
cout<<*it<<<<endl; 遍历set集合
}
lower_bound()–返回指向大于(或等于)某值的第一个元素的迭代器
upper_bound()–返回大于某个值元素的迭代器
empty() 堆栈为空则返回真
pop() 移除栈顶元素
push() 在栈顶增加元素
size() 返回栈中元素数目
top() 返回栈顶元素
vector<int> a;
sort(a.begin() + 3, a.end()); 向量排序
(3)a.back(); //返回a的最后一个元素
(4)a.front(); //返回a的第一个元素
(6)a.clear(); //清空a中的元素
(8)a.pop_back(); //删除a向量的最后一个元素
(9)a.erase(a.begin()+1,a.begin()+3); //删除a中下标为1,2的元素
(10)a.push_back(5); //在a的最后一个向量后插入一个元素,其值为5
(11)a.insert(a.begin()+1,5); //把5插入到下标为1的位置,如a为1,2,3,4,插入元素后为1,5,2,3,4
(12)a.insert(a.begin()+1,3,5); //在下标为1的位置插入3个数,其值都为5
(13)a.insert(a.begin()+1,b+3,b+6); //b为数组,在a下标为1的位置,插入b下标3,4,5的元素,如b为1,2,3,4,5,9,8,插入元素后为1,4,5,9,2,3,4,5,9,8
(14)a.size(); //返回a中元素的个数;数据类型为unsigned int
(20)a==b; //b为向量,向量的比较操作还有!=,>=,<=,>,<
当对map对象传入一个不存在的key值时,会返回默认零值。
map可以用类似于数组下标的形式直接访问值和设置值。
同样的,map默认会按照key值的升序进行排序,所以不要设置key为结构体,可以为结构体指针。
map和set的方法类似,其中erase()方法,均可传入迭代器或key值。
map的使用和遍历方法如下:
map<int, int> m;
m[1] = 10;
m[3] = 200;
m[2] = 30;
m.erase(1);
for(auto v : m){
cout << v.first << " " << v.second << endl;
}
cout << m.size() << endl;
cout << m.count(1) << endl;
cout << m[4] << endl;
Bian是一个自定义的结构体类型
bool operator==(const Bian bs1, const Bian bs2)
{
if(bs1.x == bs2.x && bs1.y == bs2.y)
{
return true;
}
return false;
}
bool operator<(const Bian bs1, const Bian bs2)
{
if(bs1.x == bs2.x && bs1.y == bs2.y)
{
return false;
}
return true;
}
bool operator>(const Bian bs1, const Bian bs2)
{
if(!(bs1 < bs2) && !(bs1 == bs2))
{
return false;
}
return true;
}
java排序有个大坑,排序函数返回值有-1,0,1三种情况,而且三种情况不能有交集,也就是说一定要满足可逆比较,假如比较o1和o2返回的是1那么反过来比较的时候返回的一定得是-1,假如返回的是0那么反过来比较时返回的一定也得是0。
下面这种写法是ok的
@Override
public int compare(Edge o1, Edge o2) {
if(o1.w > o2.w) {
return 1;
}
else if(o1.w == o2.w) {
return 0;
}
else {
return -1;
}
}
但下面这种写法是不行的,数据达到几十万的时候,会抛错Comparison method violates its general contract
@Override
public int compare(Edge o1, Edge o2) {
if(o1.w > o2.w) {
return 1;
}
return -1;
}
比较两个Integer相等不能使用 == ,必须使用equals方法
最好的方法,是通过Integer.intValue()方法获取int值,然后再比较大小
package demo01;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
// 升序
class AscCmp implements Comparator<Integer>{
@Override
public int compare(Integer o1, Integer o2) {
if(o1.intValue() > o2.intValue()) {
return 1;
}
else if(o1.intValue() == o2.intValue()){
return 0;
}
else{
return -1;
}
}
}
// 降序
class DescCmp implements Comparator<Integer>{
@Override
public int compare(Integer o1, Integer o2) {
if(o1.intValue() > o2.intValue()) {
return -1;
}
else if(o1.intValue() == o2.intValue()){
return 0;
}
else{
return 1;
}
}
}
public class Main{
public static void main(String[] args) {
Integer[] arr = {10000000, 2, 3, 4, 5}; // 排序数组只能用Integer
List<Integer> list = new ArrayList<>();
for(int i : arr) { // list转数组和数组转list最好手动遍历转换
list.add(i);
}
Arrays.sort(arr, 0, 5, new AscCmp()); //数组排序比较灵活,能够指定起始下标
Collections.sort(list, new DescCmp());
for(int i : arr) {
System.out.println(i);
}
for(int i : list) {
System.out.println(i);
}
}
}
注意字符串比大小,一定要用equals方法!!!!!
字符可以直接当作整数,整数转为字符需要强转
字符串可以转换为字符数组,字符数组可以转换为字符串
java类型的转换,往往可以通过类的valueOf方法实现。
int a = 1;
char c = (char)a;
int b = c + 1;
String s = "123456789";
char[] arr = s.toCharArray();
String s1 = String.valueOf(arr);
String s2 = String.valueOf(arr[1]);
String s3 = new String(arr);
字符串转数字:
String s1 = "123";
String s2 = "1.14";
int a = Integer.valueOf(s1);
double b = Double.valueOf(s2);
System.out.println(a + b);
字符串方法:
public int length()
//字符串长度
public char charAt(int index)
//返回某下标对应的字符
public int compareTo(String anotherString)
// 按字典序比较大小,大于返回正数,小于返回复数,等于返回0
public boolean equals(Object anObject)
//在两个字符串相等的时候返回true,否则返回false.
public String substring(int beginIndex[, int endIndex])
//返回从beginIndex位置起至endIndex-1结束的字串,如不指定endIndex则一直到末尾.
public boolean startsWith(String prefix)
//如果以指定前缀开头,返回true,否则返回false.
public boolean endsWith(String suffix)
//如果以指定后缀结尾,返回true,否则返回false.
public int indexOf(int ch[, int fromIndex])
//从fromIndex开始往后搜索,字符ch第一次出现的位置.
public int indexOf(string s[, int fromIndex])
//从fromIndex开始往后搜索,字符串s第一次出现的位置.
public String replace(char oldChar,char newChar)
//该方法用字符newChar替换当前字符串中所有的字符oldChar,并返回一个新的字符串.
public String replaceFirst(String regex, String replacement)
// 把等于regex的第一个子串替换为replacement
public String replaceAll(String regex, String replacement)
// 把等于regex的所有字串替换为replacement
^ 匹配开头,$ 匹配末尾。
java里字符串的matches方法可以判断是否匹配正则表达式,但和js有略微不同
String s = "hello";
System.out.println(s.matches("he"));
System.out.println(s.matches("he.*"));
输出是:
false
true
let s = 'hello'
console.log(/he/.test(s))
console.log(/he.*/.test(s))
输出是:
true
true