欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基于if-else的代码优化和几道力扣算法题解

程序员文章站 2022-03-16 14:54:56
一.Leetcode算法题20.有效的括号题目描述:给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。有效字符串需满足:左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。注意空字符串可被认为是有效字符串。思路:我个人做这类匹配类题的思路就是先找到不匹配的情况,在这些不匹配的基础上找到匹配的情况。这道题也是栈的一种经典运用,运用栈后进先出的特点,从栈顶开始弹栈,如果栈顶元素与要比较的元素相互对应且最后栈为空栈,那么就是有效括号,否...

一.Leetcode算法题

20.有效的括号

题目描述:

给定一个只包括 '(',')','{','}','[',']' 的字符串,
判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

思路:

我个人做这类匹配类题的思路就是先找到不匹配的情况,
在这些不匹配的基础上找到匹配的情况。
这道题也是栈的一种经典运用,运用栈后进先出的特点,
从栈顶开始弹栈,如果栈顶元素与要比较的元素相互对应且最后栈为空栈,
那么就是有效括号,否则是无效括号。同时,
这道题还有隐藏条件就是输入的字符串必须是一个偶数长度的字符串,
否则就一定会有栈顶元素多余,
不是有效的括号,可以利用这点来提前return

代码实现:

class Solution {
   public boolean isValid(String s) {
        if(s.length()%2==0){
            Stack<Character> stack=new Stack<>();
            for(int i=0;i<s.length();i++){
                char c=s.charAt(i);
                if(c=='('||c=='['||c=='{'){
                    stack.push(c);
                }
                else if(c==')'){
                    if(!stack.isEmpty()&&stack.peek()=='('){stack.pop();}
                    else{return false;}
                }
                else if(c=='}'){
                    if(!stack.isEmpty()&&stack.peek()=='{'){stack.pop();}
                    else{return false;}
                }
                else{
                    if(!stack.isEmpty()&&stack.peek()=='['){stack.pop();}
                    else{return false;}
                }
            }
            return stack.isEmpty();
        }
        return false;
    }
}

206.反转链表

题目描述:

反转一个单链表

思路:

我们在遍历时,因为既要改变当前正遍历的结点,
又要使用当前结点,
所以需要使用两个变量,
一个变量q将当前结点取出作为新头,
一个变量p作为当前正在遍历的结点,
然后不断遍历,每次遍历时,都要把q作为新头

代码:

public ListNode reverseList(ListNode head) {
        if(head==null){
            return null;
        }
        ListNode q = null;
        ListNode p = head;
        //从头开始
        while (p != null) {
            //下一个结点
            ListNode next = p.next;
            //把这个结点单独从链表中取出,暂时存储,并且需要让这个结点变成新的头,所以next要指向null或者是原来的头
            p.next = q;
            //再把这个结点作为新头
            q = p;
            //当前结点后移
            p = next;
        }
        return q;
    }

66.加一

题目描述:

给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。

最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。

你可以假设除了整数 0 之外,这个整数不会以零开头。

思路:

由题意我们知道加一的情况只有两种,一种是除9以外的数字,
一种是9,如果从个位开始,是9,那么就开始赋0,
直到第一个不是9的位置返回,
加一得十进一位个位数为 0 
加法运算如不出现进位就运算结束了且进位只会是一。
所以只需要判断有没有进位并模拟出它的进位方式,
如十位数加 1个位数置为 0,
如此循环直到判断没有再进位就退出循环返回结果。
然后还有一些特殊情况就是当出现 9999、999999 之类的数字时,
循环到最后也需要进位,出现这种情况时需要手动将它进一位。

代码:

public int[] plusOne(int[] digits) {
        for (int i = digits.length - 1; i >= 0; i--) {
            if (digits[i] == 9) {
                digits[i] = 0;
            } else {
                digits[i] += 1;
                return digits;
            }
        }
        //如果所有位都是进位,则长度+1
        digits= new int[digits.length + 1];
        digits[0] = 1;
        return digits;
    }

二.代码重构

不知道大家在自己写代码的过程中是不是习惯用if-else,虽然这是一种很简单也很有效的方法,但是时间一久,整个代码看起来简直面目可憎,也不方便日后的代码重构和维护升级,最近有在学习其他人的代码重构,发现了很多很好的主意,最多的就是简化if-else

1.提前return,去除不必要的else

如果if-else代码块包含有return语句,那么我们可以考虑通过提前return来把多余的else语句省去,使代码看上去不那么的冗余

重构之前:

if(condition){
	//dosomething
}else{
	return xxxx;
}

重构之后:

if(!condition){
	return xxxx;
}
//dosometing

2.使用三目运算符

使用三目运算符可以简化某些的if-else,使代码更加简洁,更具有可读性

重构之前:

int i;
if(condition){
	i = 1; 
}else{
	i = 2;
}

重构之后:

int i = condition?1:2;

3.使用枚举

枚举类型当时在学习的使用没有太关系,后面很多地方都用到了,如Http中的ResultState

在某些时候,使用枚举也可以优化if-else逻辑分支.即可以看做一种表驱动方法

重构之前:

//state订单状态
String stateDes;
	if(state==0){
    stateDes = "未支付";
	}else if(state==1){
    stateDes = "已支付";
	}else if(state==2){
    stateDes = "未发货";
	}else if(state==3){
    stateDes = "已发货";
	}else if(state==4){
    stateDes = "已收货";
	}else{
    stateDes = "状态未知";
	}

重构之后:

首先先定义一个枚举类

public enum OrderStateEnum{
    private int state;
    private String stateDes;
    //省略getter,setter方法
    //全参构造
    UN_PAID(0,"订单未支付"),
    PAIDED(1,"订单已支付"),
    NOT_DELIVERED(2,"未发货"),
    DELIVERED(3,"已发货"),
    GOODS_RECEIVED(4,"已收货"),;
    OrderStateEnum of(int state){
        for(OrderStateEnum temp : OrderStateEnum.values()){
            if(temp.getState() == state){
                return temp;
            }
        }
        return null;
    } 
}

当我们有了上述枚举类后,重构后的代码可以优化为一行代码:

String stateDes = OrderStateEnum.of(state).getStateDes();

4.合并条件表达式:

如果有一系列条件返回一样的结果,可以将它们合并为一个条件表达式,让逻辑更加清晰。

重构之前:

double getVipDiscount() {
        if(age<18){
            return 0.8;
        }
        if("江西".equals(province)){
            return 0.8;
        }
        if(isStudent){
            return 0.8;
        }
        //do somethig
    }

重构之后:

double getVipDiscount(){
        if(age<18|| "江西".equals(province)||isStudent){
            return 0.8;
        }
        //doSomthing
    }

5.表驱动法:

表驱动法,又称之为表驱动、表驱动方法。表驱动方法是一种使你可以在表中查找信息,而不必用很多的逻辑语句(if 或 case)来把它们找出来的方法。

以下的 demo,把 map 抽象成表,在 map 中查找信息,而省去不必要的逻辑语句。

重构之前:

if (param.equals(value1)) {
    doAction1(someParams);
} else if (param.equals(value2)) {
    doAction2(someParams);
} else if (param.equals(value3)) {
    doAction3(someParams);
}
// ...

重构之后:

Map<?, Function<?> action> actionMappings = new HashMap<>(); // 这里泛型 ? 是为方便演示,实际可替换为你需要的类型

// 初始化
actionMappings.put(value1, (someParams) -> { doAction1(someParams)});
actionMappings.put(value2, (someParams) -> { doAction2(someParams)});
actionMappings.put(value3, (someParams) -> { doAction3(someParams)});

// 省略多余逻辑语句
actionMappings.get(param).apply(someParams);

6.优化逻辑结构

将条件反转使异常情况先退出,让正常流程维持在主干流程,可以让代码结构更加清晰。

重构之前:

public double getAdjustedCapital(){
    if(capital <= 0.0 ){
        return 0.0;
    }
    if(intRate > 0 && duration >0){
        return (income / duration) *ADJ_FACTOR;
    }
    return 0.0;
}

重构之后:

public double getAdjustedCapital(){
    if(capital <= 0.0 ){
        return 0.0;
    }
    if(intRate <= 0 || duration <= 0){
        return 0.0;
    }

    return (income / duration) *ADJ_FACTOR;
}

7.策略模式+工厂模式消除if-else

假设需求为,根据用户角色不同,处理相对应的服务

重构之前:

String role = "guest";
if ("guest".equals(role)) {
        System.out.println("访客方法执行");
     } else if ("common".equals(role)) {
        System.out.println("普通用户方法执行");
    } else if ("vip".equals(role)) {
        System.out.println("VIP用户方法执行");
    } else if ("svip".equals(role)){
		System.out.println("SVIP用户方法执行");	
	}
    ...

重构之后:

首先,我们把每个条件逻辑代码块,抽象成一个公共的接口,可以得到以下代码:

//角色接口
public interface RoleService {
    void showRole();
}

我们根据每个逻辑条件,定义相对应的策略实现类,可得以下代码:

//访客访问方法策略实现类
public class GuestServiceImpl implements RoleService {
    @Override
    public void showRole() {
        System.out.println("访客方法执行");
    }
}
//普通用户访问方法策略实现类
public class CommonServiceImpl implements RoleService {
    @Override
    public void showRole() {
        System.out.println("普通用户方法执行");
    }
}
//访客访问方法策略实现类
public class VipServiceImpl implements RoleService {
    @Override
    public void showRole() {
        System.out.println("VIP用户方法执行");
    }
}
//访客访问方法策略实现类
public class SvipServiceImpl implements RoleService {
    @Override
    public void showRole() {
        System.out.println("Svip用户方法执行");
    }
}

接下来,我们再定义角色工厂类,用来管理这些角色实现角色类,如下:

//角色服务工产类
public class RoleServicesFactory {

    private static final Map<String, RoleService> map = new HashMap<>();
    static {
        map.put("guest", new GuardServiceImpl());
        map.put("common", new CommonServiceImpl());
        map.put("vip", new ViplServiceImpl());
        map.put("svip",new SvipServiceImpl());
    }
    public static RoleService getRolelService(String role) {
        return map.get(role);
    }
}

使用了策略+工厂模式之后,代码变得简洁多了,如下:

public class App(){
	public static void main(String args[]){
        String role = "guest";
        RoleService roleService = RoleServicesFactory.getRoleService(role);
        roleService.showRole();
    }
}

本文地址:https://blog.csdn.net/storm_55/article/details/109911914