检查句子中的数字是否递增
使用Java字符串的split方法可以快速的将整个字符串按照空格分隔成字符串数组。
使用一个变量pre记录上一个出现的数字大小,初始值设为-1。
遍历每一个字符串,判断是否为数字,如果是则与pre比较大小,满足条件的话更新pre,否则返回false。
循环结束,返回true
class Solution {
public boolean areNumbersAscending(String s) {
String[] strs = s.split(" ");
int prev = -1;
for(int i = 0;i < strs.length;i++){
if(!isNumber(strs[i])){
continue;
}
int num = Integer.parseInt(strs[i]);
if(num <= prev){
return false;
}
prev = num;
}
return true;
}
private boolean isNumber(String str){
for(int i = 0;i < str.length();i++){
if(str.charAt(i) < '0' || str.charAt(i) > '9'){
return false;
}
}
return true;
}
}
简易银行系统
事务处理部分问题应该不大。有几个地方还是要注意以下,以防被卡:
- 账户从1开始计数,转换成下标时要-1
- 账户支出(取款或转款)时要校验余额。
- 账户存在出界情况,进行任何事务前请先校验账户合法
class Bank {
private long[] balance;
public Bank(long[] balance) {
this.balance = balance;
}
public boolean transfer(int account1, int account2, long money) {
account1--;
account2--;
if(!checkAccount(account1) || !checkAccount(account2)){
return false;
}
if(balance[account1] < money){
return false;
}
balance[account1] -= money;
balance[account2] += money;
return true;
}
public boolean deposit(int account, long money) {
account--;
if(!checkAccount(account)){
return false;
}
balance[account] += money;
return true;
}
public boolean withdraw(int account, long money) {
account--;
if(!checkAccount(account)){
return false;
}
if(balance[account] >= money){
balance[account] -= money;
return true;
}
return false;
}
private boolean checkAccount(int account){
return account >= 0 && account < balance.length;
}
}
统计按位或能得到最大值的子集数目
这道题需要我们从集合中挑出所有子集,子集中的元素相或结果等于整个集合元素相或。
从每位的角度看,题目是希望挑出的子集的元素包含所有位置的1 。
不过由于数据规模非常小,可以选择使用枚举幂集合进行统计。
class Solution {
private int ans = 0;
private int orSum = 0;
public int countMaxOrSubsets(int[] nums) {
for(int i = 0;i < nums.length;i++){
orSum |= nums[i];
}
dfs(nums,0,0);
return ans;
}
private void dfs(int[] nums,int dep,int sum){
if(dep == nums.length){
ans += sum == orSum ? 1 : 0;
return;
}
dfs(nums,dep + 1,sum);
dfs(nums,dep + 1,sum | nums[dep]);
}
}
到达目的地的第二短时间
首先,对题目的分析,可以得出一个结论:由于经过每条边的时间都是一样的且每个节点灯的状态都同步,到达每个节点的时间只与步数有关,与路径无关,步数越多,耗时越长。
接着,可以知道,要求次少时间,实际上就是要求次少的步数。
那么,如果像题目给出样例一样只有一种长度的路径怎么办?
- 题目允许我们反复到大某节点,所以这种情况应该在路径中的任意一条边折返一次达到次少步数,有 次 少 步 数 = 最 少 步 数 + 2 次少步数 = 最少步数 +2 次少步数=最少步数+2
接下来的问题就是,要如何求解每个点的最少步数和次少步数。
由于问题类似于求解单源最短路,我们可以考虑改造spfa算法或者dijkstra算法实现。
主要改造的点有:
- 顶点最短路径有两个值,最小值和次小值
- 比较节点距离时,最小值第一关键字,次小值第二关键字
- 更新节点时,需要用该节点的最小和次小分别更新后继节点的最小和次小,任一值可以更新后继就将其加入队列(spfa)或堆(dijkstra)中。
- 同一节点可能出现多次,不仅首次可能更新后续节点,第二次也可能更新后续节点的次小值,所以不要直接使用标记数组使节点仅出现一次。(可以不标记)
那么最后,就是根据我们拿到的次小步数计算答案了。这里由于步数不会很大( ≤ n + 1 \le n+1 ≤n+1)可以直接使用模拟得出答案:
- spfa实现
class Solution {
private int[] dep1; //最少次数
private int[] dep2; //次少次数
private int[] head; //邻接表头
private Edge[] nxt; //邻接表
private int tot = 0;//邻接表计数
//邻接表添加边
private void link(int x,int y){
nxt[++tot] = new Edge(y,head[x]);
head[x] = tot;
nxt[++tot] = new Edge(x,head[y]);
head[y] = tot;
}
public int secondMinimum(int n, int[][] edges, int time, int change) {
dep1 = new int[n + 1];
dep2 = new int[n + 1];
nxt = new Edge[edges.length * 3];
head = new int[n + 1];
//初始化
for(int i = 1;i <= n;i++){
dep1[i] = 1 << 30;
dep2[i] = 1 << 30;
head[i] = 0;
}
//建立邻接表
for(int[] edge : edges){
link(edge[0],edge[1]);
}
//spfa队列
int queue[] = new int[n * 10];
int l = 1,r = 0;
//初始添加起点,步数为0
queue[++r] = 1;
dep1[1] = 0;
while(l <= r){
int k = queue[l++];
//更新可能的后续节点
for(int i = head[k];i != 0;i = nxt[i].next){
Edge edge = nxt[i];
//如果可以更新成功则加入队列
if(setDep(edge.vertex,dep1[k] + 1) || setDep(edge.vertex,dep2[k] + 1)){
queue[++r] = edge.vertex;
}
}
}
//获取次少步数
int steps = dep2[n];
//无次少步数,则最少步数折返一次
if(steps == 1 << 30){
steps = dep1[n] + 2;
}
//计算次少步数时间
return calc(time,change,steps);
}
private int calc(int time,int change,int steps){
int curr = 0;
for(int i = 0;i < steps;i++){
if(isGreen(change,curr)){//当前为绿灯
curr += time;
}else{ //红灯,等到绿灯
curr = latestGreen(change,curr) + time;
}
}
return curr;
}
private boolean isGreen(int change,int curr){
curr %= (change * 2);
return curr < change;
}
private int latestGreen(int change,int curr){
return (curr / (change * 2) + 1) * (change * 2);
}
//更新步数,更新最少步数或次少步数都算更新成功
private boolean setDep(int k,int dep){
if(dep < dep1[k]){
dep2[k] = dep1[k];
dep1[k] = dep;
return true;
}else if(dep < dep2[k] && dep > dep1[k]){
dep2[k] = dep;
return true;
}
return false;
}
}
class Edge{
public int vertex;
public int next;
public Edge(int vertext,int next){
this.vertex = vertext;
this.next = next;
}
}
- dijkstra实现
class Solution {
private int[] dep1;
private int[] dep2;
private int[] head;
private Edge[] nxt;
private int tot = 0;
private void link(int x,int y){
nxt[++tot] = new Edge(y,head[x]);
head[x] = tot;
nxt[++tot] = new Edge(x,head[y]);
head[y] = tot;
}
public int secondMinimum(int n, int[][] edges, int time, int change) {
dep1 = new int[n + 1];
dep2 = new int[n + 1]
nxt = new Edge[edges.length * 3];
head = new int[n + 1];
for(int i = 1;i <= n;i++){
dep1[i] = 1 << 30;
dep2[i] = 1 << 30;
head[i] = 0;
}
for(int[] edge : edges){
link(edge[0],edge[1]);
}
PriorityQueue<Node> pq = new PriorityQueue<>();
pq.add(new Node(1,0,1 << 30));
dep1[1] = 0;
while(!pq.isEmpty()){
Node node = pq.poll();
for(int i = head[node.vertex];i > 0;i = nxt[i].next){
Edge edge = nxt[i];
if(setDep(edge.vertex,dep1[node.vertex] + 1) || setDep(edge.vertex,dep2[node.vertex] + 1)){
pq.add(new Node(edge.vertex,dep1[edge.vertex],dep2[edge.vertex]));
}
}
}
int steps = dep2[n];
if(steps == 1 << 30){
steps = dep1[n] + 2;
}
return calc(time,change,steps);
}
private int calc(int time,int change,int steps){
int curr = 0;
for(int i = 0;i < steps;i++){
if(isGreen(change,curr)){
curr += time;
}else{
curr = latestGreen(change,curr) + time;
}
}
return curr;
}
private boolean isGreen(int change,int curr){
curr %= (change * 2);
return curr < change;
}
private int latestGreen(int change,int curr){
return (curr / (change * 2) + 1) * (change * 2);
}
private boolean setDep(int k,int dep){
if(dep < dep1[k]){
dep2[k] = dep1[k];
dep1[k] = dep;
return true;
}else if(dep < dep2[k] && dep > dep1[k]){
dep2[k] = dep;
return true;
}
return false;
}
}
class Edge{
public int vertex;
public int next;
public Edge(int vertext,int next){
this.vertex = vertext;
this.next = next;
}
}
class Node implements Comparable<Node>{
public int vertex;
public int dep1;
public int dep2;
public Node(int vertex,int dep1,int dep2){
this.vertex = vertex;
this.dep1 = dep1;
this.dep2 = dep2;
}
public int compareTo(Node node){
if(this.dep1 == node.dep1){
return dep2 - node.dep2;
}
return this.dep1 - node.dep1;
}
}