【算法】Day02

文章详细介绍了四个编程问题的解决方案:如何替换字符串中的空格,从尾到头打印链表,根据前序和中序遍历重建二叉树,以及使用动态规划和递归求解斐波那契数列。每个问题都提供了代码示例,包括迭代和递归等不同方法。
摘要由CSDN通过智能技术生成

努力经营当下,直至未来明朗!


普通小孩也要热爱生活!

1. 字符串替换空格

替换空格
1)替换:修改的是原字符串
2)将空格替换为%20,也就是一个字符位置变长为三个字符位置(一个空格增两个字符);字符串长度变长,也就是原来的字符串要向后移动
3)计算新的字符串长度:原字符串长度+2*空格数
4)从后往前遍历!
5)保证下标的合法性
6)可变长字符串,重新设置一下字符串长度

代码:

public class Solution {
    public String replaceSpace(StringBuffer str) {
    	// 计算空格个数(为了计算新字符串的长度)
        int space = 0;
        for(int i=0; i<str.length(); i++) {
            if(str.charAt(i) == ' ') {
                space++;
            }
        }
        
        // 计算字符串长度以及最末指针
        int new_length = str.length() + 2*space;
        int old_index = str.length()-1;
        int new_index = new_length - 1;

        // 设定新的字符串长度
        str.setLength(new_length);

        // 进行循环替换(合法性判断)
        while(new_index>=0 && old_index>=0) {
            if(str.charAt(old_index) == ' ') {
                // new_index:先用后减
                str.setCharAt(new_index--,'0');
                str.setCharAt(new_index--,'2');
                str.setCharAt(new_index--,'%');
                old_index--;
            } else {
                // 直接进行赋值替换就行
                str.setCharAt(new_index,str.charAt(old_index));
                new_index--;
                old_index--;
            }
        }
        return str.toString();
    }
}


2. 链表相关:从尾到头打印链表

从尾到头打印链表
1)思路:

①逆序 -> 定义栈结构;
②遍历后保存在数组中;
③递归(重点!

2)代码:
① 栈结构:

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
import java.util.Stack;

public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        // 用来保存出栈的元素
        ArrayList<Integer> list = new ArrayList<>();

        // 首先进行判空操作
        if(listNode == null) {
            return list;
        }

        // 不空的情况下:进行入栈操作
        Stack<Integer> stack = new Stack<>(); 
        while(listNode != null) {
            stack.push(listNode.val);
            listNode = listNode.next;
        }

        // 然后出栈存入list中
        while(!stack.empty()) {
            list.add(stack.pop());
        }
        
        return list;
    }
}

② 递归——如果要将前面的元素加入到新链表中,就要先完成之后元素加入链表。

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
public class Solution {
    // 重写方法
    private static void printListFromTailToHead(ArrayList<Integer> list,ListNode listNode) {
        if(listNode == null) {
            return;
        }
        printListFromTailToHead(list,listNode.next);
        list.add(listNode.val);
    }
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> list = new ArrayList<>();
        printListFromTailToHead(list,listNode);
        return list;
    }
}


3. 重建二叉树

重建二叉树
1)二叉树:前中后序遍历(针对根结点)
2)方法:从前序遍历中找到根结点(首元素),然后拿着该根结点去中序遍历中找,然后就可以将中序遍历划分为左右子树,然后每棵子树又可以根据自己的根结点再划分为左右子树;而中序遍历的根结点左边有几个元素就代表前序遍历往后数几个元素都是左子树的元素,再之后的元素就是右子树元素。也就是:递归!
3)思路:针对前序和中序遍历划分根结点以及左右子树
4)一定要注意条件判断!!

代码:

import java.util.*;
/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    // 这里使用的是: 闭区间!
    private static TreeNode reConstructBinaryTree(int[] pre,int pre_start,int pre_end,int[] vin,int vin_start,int vin_end) {
        // 判断条件:注意这个条件一定要存在!!否则编译失败!
        if(pre_start>pre_end || vin_start>vin_end) {
            return null;
        }
        
        // 根结点:前序遍历的第一个元素就是
        TreeNode root = new TreeNode(pre[pre_start]);
        // 然后再中序遍历中找到根结点位置
        // 注意开始遍历的位置!
        for(int i=vin_start; i<=vin_end; i++) {
            if(root.val == vin[i]) {
                // 找到了根结点,然后开始构建左右子树
                // 一定要注意参数!!
                // 左子树
                root.left = reConstructBinaryTree(pre,pre_start+1,pre_start+1+i-vin_start-1,vin,vin_start,i-1);
                // 右子树
                root.right = reConstructBinaryTree(pre,pre_start+1+i-vin_start,pre_end,vin,i+1,vin_end);

                break;
            }
        }
        
        return root;
    }
    public TreeNode reConstructBinaryTree(int [] pre,int [] vin) {
        // 首先进行判断
        if(pre==null || vin==null || pre.length!=vin.length) {
            return null;
        }

        // 其实关键就是:找到根结点以及左右子树
        return reConstructBinaryTree(pre,0,pre.length-1,vin,0,vin.length-1);
    }
}

4. fib数列[动态规划]

菲波那切数列
1)fib:0 1 1 … 后面的项就是前两项之和
2)思路:① 迭代; ② 递归(递归+剪枝!
3)代码:
① 迭代:3)循环(注意循环条件)以及third的初始值

public class Solution {
    public int Fibonacci(int n) {
        if(0 == n) {
            return n;
        }

        int first = 1;
        int second = 1;
        int third = 1; // 定义1是方便不判断first、second就直接输出
        while(n > 2) {
            third = first + second;
            first = second;
            second = third;
            n--; // 一定要注意循环条件的改变!
        }
        return third;
    }
}

② 递归:递归(重复计算+调用函数成本,会使效率变低!一般不推荐使用

public class Solution {
    public int Fibonacci(int n) {
        if(0 == n) {
            return 0;
        }

        if(n <= 2) {
            return 1;
        }

        return Fibonacci(n-1) + Fibonacci(n-2);
    }
}

如果要使用递归的话,就进行剪枝操作(递归+剪枝
剪枝:其实就是需要借助Map进行存储,每次需要fib的时候就查看在map中是否存在,存在就直接使用,不存在就计算后存入map。

import java.util.*;

public class Solution {
    // 递归+剪枝(Map)
    // 注意:是Map = HashMap
     private Map<Integer,Integer> map = new HashMap<>();
    public int Fibonacci(int n) {
        if(n==0 || n==1) {
            return n;
        }
        if(n == 2) {
            return 1;
        }

        // 进行递归+剪枝
        int ppre = 0; // n-2
        if(map.get(n-2) == null) {
            // 说明该值在map中不存在
            // 计算并加入
            ppre = Fibonacci(n-2);
            map.put(n-2,ppre);
        } else {
            // 此时说明找到
            ppre = map.get(n-2);
        }

        int pre = 0; // n-1
        if(map.get(n-1) == null) {
            // 说明该值在map中不存在
            // 计算并加入
            pre = Fibonacci(n-1);
            map.put(n-1,pre);
        } else {
            // 此时说明找到
            pre = map.get(n-1);
        }

        return ppre + pre;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

'Dream是普通小孩耶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值