import java.util.*;
class Solution {
public int romanToInt(String s) {
int sum=0;
int finalnum=0;
for(int i=0;i<s.length()-1;i++){
int prenum=getValue(s.charAt(i));
int num=getValue(s.charAt(i+1));
if(prenum<num){
sum=sum-prenum;
}else{
sum=sum+prenum;
}
finalnum=num;
}
sum=sum+finalnum;
return sum;
}
private int getValue(char ch){
switch(ch){
case 'I':return 1;
case 'V':return 5;
case 'X':return 10;
case 'L':return 50;
case 'C':return 100;
case 'D':return 500;
case 'M':return 1000;
default: return 0;
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-koWCmyYY-1611670523520)(C:\Users\HASEE\AppData\Roaming\Typora\typora-user-images\1611461674333.png)]
错误例子如上图。
原因在于我的循环用的怪怪的。等于是假设了字符串至少有两位,遇到只有一位的情况出错了。
正确解法如下:
import java.util.*;
class Solution {
public int romanToInt(String s) {
int sum=0;
int prenum=getValue(s.charAt(0));
for(int i=1;i<s.length();i++){
int num=getValue(s.charAt(i));
if(prenum<num){
sum=sum-prenum;
}else{
sum=sum+prenum;
}
prenum=num;
}
sum=sum+prenum;
return sum;
}
private int getValue(char ch){
switch(ch){
case 'I':return 1;
case 'V':return 5;
case 'X':return 10;
case 'L':return 50;
case 'C':return 100;
case 'D':return 500;
case 'M':return 1000;
default: return 0;
}
}
}
import java.util.*;
class Solution {
public String longestCommonPrefix(String[] strs){
if(strs == null||strs.length==0){
return "";
}
int count=strs.length;
int length=strs[0].length();
for(int i=0;i<length;i++){
char c=strs[0].charAt(i);
for(int j=1;j<count;j++){
if(i==strs[j].length()||strs[j].charAt(i) != c){
//重点复习
return strs[0].substring(0,i);
}
}
}
return strs[0];
}
}
错误:
import java.util.*;
class Solution {
public String longestCommonPrefix(String[] strs){
if(strs == null||strs.length==0){
return "";
}
int count=strs.length;
int length=strs[0].length();
for(int i=0;i<length;i++){
char c=strs[0].charAt(i);
for(int j=1;j<count;j++){
if(strs[j].charAt(i) != c||i==strs[j].length()){
//重点复习
return strs[0].substring(0,i);
}
}
}
return strs[0];
}
}
import java.util.HashMap;
class Solution {
public boolean isValid(String s) {
Map<Character,Character> pair=new HashMap<Character,Character>(){
{
put(')','(');
put(']','[');
put('}','{');
}};
Deque<Character> stack=new LinkedList<Character>();
for(int i=0;i<s.length();i++){
char ch=s.charAt(i);
if(pair.containsKey(ch)){
if(stack.isEmpty()||stack.peek()!=pair.get(ch)){
return false;
}
stack.pop();
}else{
stack.push(ch);
}
}
return stack.isEmpty();
}
}
HashMap的初始化值得注意。声明时初始化速度较快。
栈也是一种表。pop()弹出栈顶值,peek()访问栈顶值。
解法很妙。
import java.util.HashMap;
class Solution {
public boolean isValid(String s) {
Map<Character,Character> pair=new HashMap<Character,Character>();
pair.put(')','(');
pair.put(']','[');
pair.put('}','{');
//这种初始化方法较上面声明时初始化速度慢。
Deque<Character> stack=new LinkedList<Character>();
for(int i=0;i<s.length();i++){
char ch=s.charAt(i);
if(pair.containsKey(ch)){
if(stack.isEmpty()||stack.peek()!=pair.get(ch)){
return false;
}
stack.pop();
}else{
stack.push(ch);
}
}
return stack.isEmpty();
}
}
当一个函数用它自己来定义时就称为是递归。
不断剔除两个链表中的最小值
解法一:递归
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 ==null){
return l2;
}
if(l2 ==null){
return l1;
}
if(l1.val<l2.val){
l1.next=mergeTwoLists(l1.next,l2);
return l1;
}else{
l2.next=mergeTwoLists(l1,l2.next);
return l2;
}
}
}
方法巧妙,但也难想。
思路就是函数功能是返回两个链表的最小值。递归一次返回一个最小值然后将剩下的节点再输入函数作递归,一步步直到出现空链表,递归结束。
解法二:迭代
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
ListNode prehead=new ListNode(-1);//prehead是头节点
ListNode prev=prehead;//prev是移动节点
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
/*if(l1 ==null){
return l2;
}
if(l2 ==null){
return l1;
}
if(l1.val
while(l1!= null&&l2!=null){
if(l1.val<l2.val){
prev.next=l1;
l1=l1.next;
}else{
prev.next=l2;
l2=l2.next;
}
prev=prev.next;
}
prev.next=l1==null?l2:l1;
return prehead.next;//从第二个节点开始返回
}
}
class Solution {
public int removeDuplicates(int[] nums) {
if(nums.length==0) return 0;
int i=0;
for(int j=1;j<nums.length;j++){
if(nums[j]!=nums[i]){
i++;
nums[i]=nums[j];
}
}
return i+1;
}
}
这个解法双指针用的巧妙,自愧不如。人这双指针真是优雅。
i是慢指针,j是快指针,只有找到不同值时i+1,把nums[j]的值赋给nums[i+1],nums[j]=nums[i]时就让快指针加。
package com.leetcode;
import com.BeforeShiErZhang.QuadrangleUseInterface;
public class question {
public int removeDuplicates(int[] nums) {
int length = 0;
for (int i = 0; i < nums.length; i++) {
int j=i;
while(j<nums.length&&nums[j]==nums[i]){
j++;
}
length = i ;
}
return length;
}
public static void main(String[] args) {
question q1=new question();
System.out.println(q1.removeDuplicates(new int[]{
0, 0, 1, 1, 1, 2, 2, 3, 3, 4}));
}
}
这是我的解法,在内层循环中找到不一样的值之后不知道怎么停下来,只能一直找到最大的。
class Solution {
public int removeElement(int[] nums, int val) {
int i=0;
for(int j=0;j<nums.length;j++){
if(nums[j]!=val){
nums[i]=nums[j];
i++;
}
}
return i;
}
}
class Solution {
public int strStr(String haystack, String needle) {
//解法一:滑动窗口
/* int n=haystack.length();
int L=needle.length();
for(int start=0;start
//解法二:双指针
int n=haystack.length();
int L=needle.length();
if(L==0) return 0;
int pn=0;
while(pn<n-L+1){
while(pn<n-L+1&&haystack.charAt(pn)!=needle.charAt(0)) ++pn;
int pl=0;
int err=0;
while(pl<L&&pn<n&&haystack.charAt(pn)==needle.charAt(pl)){
++pn;
++pl;
++err;
}
if(err==L) return pn-L;
pn=pn-err+1;//当字符串并不完全匹配时,返回到起始位置加1的位置重新匹配。
}
return -1;
}
}
class Solution {
public String countAndSay(int n) {
if(n==1) return "1";//递归的第一件事就是要确定递归结束条件。
String str=countAndSay(n-1);//上一轮的输出是这一轮的输入,这就是递归。
StringBuffer ans=new StringBuffer();
int start=0;
//提供此解法的大神说“递归代码最神的地方就是一个循环可以展现出n个嵌套for()循环。
//这里的算法在初级算法Lc中经常用到,当与前一个元素不一样时出发函数
//从1开始是为了方便对比,长度也+1方便对比”
for(int i=1;i<str.length()+1;i++){
//必须得是str.length()+1,因为遍历到最后一位时,不管最后两位相等与否,都需要i+1,来描述最后一位或最后两位数字的个数。
if(i==str.length()){
ans.append(i-start).append(str.charAt(start));
}else if(str.charAt(i)!=str.charAt(start)){
ans.append(i-start).append(str.charAt(start));//StringBuffer类可以直接对StringBuffer对象本身操作,而不是生成新的对象。 像本例的append()方法,直接添加字符进入字符串,最后直接toString()转换为字符串,功能强大。
start=i;//双指针遍历
}
}
return ans.toString();
}
}
class MinStack {
Deque<Integer> xstack;
Deque<Integer> minStack;
/** initialize your data structure here. */
public MinStack() {
xstack=new LinkedList<Integer>();
minStack=new LinkedList<Integer>();
minStack.push(Integer.MAX_VALUE);//缺少这行代码会报空指针错。
//原因是:pop()、top()、getMin()操作总是在非空栈上调用,栈不能空,所以在初始化的时候提前加了一个最大值。
}
public void push(int x) {
xstack.push(x);
minStack.push(Math.min(minStack.peek(),x));
}
public void pop() {
xstack.pop();
minStack.pop();
}
public int top() {
return xstack.peek();
}
public int getMin() {
return minStack.peek();
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(x);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
class MyStack {
//两个队列实现
/*Queue queue1;
Queue queue2;
/** Initialize your data structure here. */
/*public MyStack() {
queue1=new LinkedList();
queue2=new LinkedList();
}
/** Push element x onto stack. */
/*public void push(int x) {
queue2.offer(x);
//if(queue1.isEmpty()){//queue1里面元素不止一个,应用循环。
while(!queue1.isEmpty()){
queue2.offer(queue1.poll());
}
Queue temp=queue2;
queue2=queue1;
queue1=temp;
}
/** Removes the element on top of the stack and returns that element. */
/*public int pop() {
int b=queue1.peek();
queue1.poll();
return b;
}
/** Get the top element. */
/* public int top() {
return queue1.peek();
}
/** Returns whether the stack is empty. */
/* public boolean empty() {
return queue1.isEmpty();
}*/
//一个队列实现
/** Initialize your data structure here. */
Queue<Integer> queue;
public MyStack() {
queue=new LinkedList<Integer>();
}
/** Push element x onto stack. */
public void push(int x) {
int n=queue.size();
queue.offer(x);
for(int i=0;i<n;i++){
queue.offer(queue.poll());
}
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
return queue.poll();
}
/** Get the top element. */
public int top() {
return queue.peek();
}
/** Returns whether the stack is empty. */
public boolean empty() {
return queue.isEmpty();
}
}
/**
* Your MyStack object will be instantiated and called as such:
* MyStack obj = new MyStack();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.top();
* boolean param_4 = obj.empty();
*/
class MyQueue {
Deque<Integer> stack1;
Deque<Integer> stack2;
int front;
/** Initialize your data structure here. */
public MyQueue() {
stack1=new LinkedList<Integer>();
stack2=new LinkedList<Integer>();
}
/* Push element x to the back of queue. */
public void push(int x) {
//解法一
/* while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
stack1.push(x);
while(!stack2.isEmpty()){
stack1.push(stack2.pop());
}*/
//解法二
if(stack1.isEmpty()){
front=x;
}
stack1.push(x);
}
/** Removes the element from in front of queue and returns that element. */
public int pop() {
//解法一
//return stack1.pop();
//解法二
if(stack2.isEmpty()){
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
/** Get the front element. */
public int peek() {
//解法一:return stack1.peek();
//解法二:
if(stack2.isEmpty()){
return front;
}else{
return stack2.peek();
}
}
/** Returns whether the queue is empty. */
public boolean empty() {
//解法一:return stack1.isEmpty();
//解法二:
return stack2.isEmpty()&&stack1.isEmpty();
}
}
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = new MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.empty();
*/
单调栈+哈希map
//本人解法
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
Deque<Integer> stack=new LinkedList<Integer>();
Map<Integer,Integer> map=new HashMap<Integer,Integer>();
int ans[]=new int[nums1.length];
for(int i=0;i<nums2.length;i++){
while((!stack.isEmpty())&&nums2[i]>stack.peek()){
map.put(stack.pop(),nums2[i]);
}
stack.push(nums2[i]);
}
for(int i=0;i<nums1.length;i++){
if(map.containsKey(nums1[i])){
ans[i]=map.get(nums1[i]);
}else{
ans[i]= -1;
}
}
return ans;
}
}
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
Deque<Integer> stack=new LinkedList<Integer>();
Map<Integer,Integer> map=new HashMap<Integer,Integer>();
int ans[]=new int[nums1.length];
for(int i=0;i<nums2.length;i++){
while((!stack.isEmpty())&&nums2[i]>stack.peek()){
map.put(stack.pop(),nums2[i]);
}
stack.push(nums2[i]);
}
//本人用for()循环实现
/*for(int i=0;i
//官方题解:
while(!stack.isEmpty()){
map.put(stack.pop(),-1);//栈中最后剩下的元素跟-1对应起来。
}
for(int i=0;i<nums1.length;i++){
ans[i]=map.get(nums1[i]);
}
return ans;
}
}
首先想到用哈希map记录x,+,D,C分别对应得操作,但是不知如何实现对前面得分的操作。
既然是栈这一节,考虑能不能用栈实现?
突然想到能不能用递归?因为有些操作是对前次得分的操作,函数最后返回的是得分。但是递归结束条件不是很明显。
将字符串入栈,x入栈,+把栈的元素弹出并且入栈(能够将前两次的值弹出加起来再分别入栈吗)(可以实现),c就把栈顶元素删除,D就取栈顶值2入栈。
class Solution {
public int calPoints(String[] ops) {
int ans=0;
Deque<Integer> stack=new LinkedList<Integer>();
for(int i=0;i<ops.length;i++){
if(ops[i].equals("+")){
int a=stack.pop();
int b=stack.peek();
//int b=stack.pop();
// stack.push(b)
stack.push(a);
stack.push(a+b);
}else if(ops[i].equals("D")){
stack.push(stack.peek()*2);
}else if(ops[i].equals("C")){
stack.pop();
}else{
stack.push(Integer.parseInt(ops[i]));
}
}
while(!stack.isEmpty()){
ans=stack.pop()+ans;
}
return ans;
}
}
两个方法内存消耗差0.lMB,全国排名差了60%。
本题需要先对字符串进行处理,之后再比较
退格字符串左侧字母删掉
需对字符串操作
遍历字符串找到所有退格字符,将其左侧字符删掉。
可考虑将字符串入栈,当遇到退格字符时,栈顶值pop。当栈为空遇到退格字符不操作。
对两个栈中元素进行比较,循环出栈。
class Solution {
public boolean backspaceCompare(String S, String T) {
//自己解法:
/*Deque stack1=new LinkedList();
Deque stack2=new LinkedList();
for(int i=0;i
//官方解法:重构字符串
return build(S).equals(build(T));
}
public String build(String str){
StringBuffer ret=new StringBuffer();
int length=str.length();
for(int i=0;i<length;i++){
char ch=str.charAt(i);
if(ch!='#'){
ret.append(ch);
}else{
if(ret.length()>0){
ret.deleteCharAt(ret.length()-1);
}
}
}
return ret.toString();
}
}
/
//双指针
class Solution {
public boolean backspaceCompare(String S, String T) {
//自己解法:
/*Deque stack1=new LinkedList();
Deque stack2=new LinkedList();
for(int i=0;i
//官方解法:
/* return build(S).equals(build(T));
}
public String build(String str){
StringBuffer ret=new StringBuffer();
int length=str.length();
for(int i=0;i0){
ret.deleteCharAt(ret.length()-1);
}
}
}
return ret.toString();*/
//双指针:
int i=S.length()-1,j=T.length()-1;
int skipS=0,skipT=0;
while(i>=0 || j>=0){
//当两个字符串的指针都小于0退出循环
while(i>=0){
//对字符串s处理,若是#则skipS加一,说明前面多一个被抵消的字符。
//若不是#且skipS>0说明是个需要删掉的字符。两者都不是则是需要保留的字符,跳出循环去跟另一个字串比较。
if(S.charAt(i)=='#'){
skipS++;
i--;
}else if(skipS>0){
skipS--;
i--;
}else{
break;
}
}
while(j>=0){
if(T.charAt(j)=='#'){
skipT++;
j--;
}else if(skipT>0){
skipT--;
j--;
}else{
break;
}
}
//判断条件:
//如果这个字符不相等,直接返回false
//如果这个字符只是一个字串有,另一个字串指针已经<0,则数目不匹配。
//这里之所以要排除return false而不是直接限定相等的情况,是因为这只是判断一个字符,即使判断出相等也无法返回true,相反判断出不相等可以直接返回false。
if(i>=0&&j>=0){
if(S.charAt(i)!=T.charAt(j)){
return false;
}
}else{
if(i>=0||j>=0){
return false;
}
}
i--;
j--;
}
return true;//当两个字符都遍历完之后,若还是不不相等,则返回true。
}
}
将问题分为两部分,原语化分解和去外括号
将括号字符串堆栈,当入栈值与栈顶值对应则弹出,并重新入栈2,当栈弹空时即为外括号将其去掉。
通过判断栈为空可以找到一个原语。
如何去掉外括号呢?问题在于这种括号(()),如果按顺序出栈就会分成两个括号。
class Solution {
public String removeOuterParentheses(String S) {
StringBuilder ans=new StringBuilder();
Stack<Character> stack=new Stack<>();
int start=0;
int end=0;
boolean flag=false;
for(int i=0;i<S.length();i++){
char ch=S.charAt(i);
if(ch=='('){
stack.push(ch);
if(!flag){
start=i;
flag=true;
}
}
if(ch==')'){
stack.pop();
if(stack.isEmpty()){
end=i;
ans.append(S.substring(start+1,end));
flag=false;
start=end;
}
}
}
return ans.toString();
}
}
将字符串入栈,判断栈是否为空,如果为空则入栈,不为空判断与栈顶元素是否相同,相同则弹出栈顶元素,否则继续入栈。
class Solution {
public String removeDuplicates(String S) {
Deque<Character> stack=new LinkedList<>();
StringBuffer ans=new StringBuffer();
for(int i=0;i<S.length();i++){
if(stack.isEmpty()||stack.peek()!=S.charAt(i)){
stack.push(S.charAt(i));
}else {
if(stack.peek()==S.charAt(i))
stack.pop();
}
}
while(!stack.isEmpty()){
ans.append(stack.pop());
}
return ans.reverse().toString();
}
}
只要读到不与数组索引差一的数字就输出push,pop,其他数字push。不能这样考虑
双指针,i是列表指针,j是数组指针,for()循环循环遍历列表,计算数组值与列表值差值作为push还是push、pop判断依据。
当数组值与列表值相等(i+1即是列表值)时输入Push,注意得是大写。
当数组值比列表值大,差值为circle。则需循环输出circle次Push、Pop,由于存在for()循环,i每循环一次会+1,则我们输出circle次Push、Pop对应i递增circle-1次,最后一次由for()循环递增,实现将中间元素过滤的功能,找到目标元素。
现在做题分3个步骤:
class Solution {
public List<String> buildArray(int[] target, int n) {
List<String> ans=new ArrayList<>();
int j=0;
int circle=0;
for(int i=0;i<n;i++){
circle=target[j]-i-1;
if(circle==0){
ans.add("Push");
j++;
}else{
for(int d=0;d<circle;d++){
ans.add("Push");
ans.add("Pop");
}
for(int m=0;m<circle-1;m++){
i++;
}
}
if(j==target.length) break;
}
return ans;
}
}
本题将字符串入栈,用当前字符与栈顶值比较,若为大小写则弹出栈顶值,否则入栈。
关键在于是否互为大小写的判定,当两个字符不相等且都转化为小写却相等时互为大小写。
class Solution {
public String makeGood(String s) {
StringBuffer ans=new StringBuffer();
Deque<Character> stack=new LinkedList<>();
for(int i=0;i<s.length();i++){
if(stack.isEmpty()){
stack.push(s.charAt(i));
}else if( ! ((stack.peek()!=s.charAt(i)) && (Character.toLowerCase( stack.peek()) ==Character.toLowerCase( s.charAt(i)))) ){
stack.push(s.charAt(i));
}else{
stack.pop();
}
}
while(!stack.isEmpty()){
ans.append(stack.pop());
}
return ans.reverse().toString();
}
}
class Solution {
public String makeGood(String s) {
/* StringBuffer ans=new StringBuffer();
Deque stack=new LinkedList<>();
for(int i=0;i
//官方解法
StringBuffer ret=new StringBuffer();
int retIndex=-1;
int length=s.length();
for(int i=0;i<length;i++){
char ch=s.charAt(i);
if(ret.length()>0 && Character.toLowerCase(ret.charAt(retIndex))==Character.toLowerCase(ch)&&ret.charAt(retIndex)!=ch){
ret.deleteCharAt(retIndex);
retIndex--;
}else{
ret.append(ch);
retIndex++;
}
}
return ret.toString();
}
}
将字符串列表入栈,遍历字符串列表,对每一项进行如下判断:
最后返回栈内元素数量
class Solution {
public int minOperations(String[] logs) {
Deque<String> Stack=new LinkedList<>();
for(int i=0;i<logs.length;i++){
if((!logs[i].equals("../"))&&(!logs[i].equals("./"))){
Stack.push(logs[i]);
}else {
if(logs[i].equals("../")&&!Stack.isEmpty()) Stack.pop();
}
}
int j=0;
while(!Stack.isEmpty()){
Stack.pop();
j++;
}
return j;
}
}
//不使用栈,直接计数,速度1ms,内存37.8MB.
class Solution {
public int minOperations(String[] logs) {
int count=0;
for(String log:logs){
if(log.equals("../")){
if(count==0) continue;
count--;
}else if(log.equals("./")){
continue;
}else{
count++;
}
}
return count;
}
}