写点什么

ARTS 打卡第 7 周

作者:苏籍
  • 2023-10-01
    北京
  • 本文字数:5469 字

    阅读完需:约 18 分钟

Algorithm


字符串相加


思路:因为可能超过 Integer 最大值,所以用竖式相加 方式,用每一位进行计算,并保留进位。

将进位参与下一位的计算中

字符串长短不一,对于短的地方进行补 0 即可

class Solution {

public String addStrings(String num1, String num2) { // 竖式计算,从末位开始 相加,如果大于10将 进行进位。 有可能不相等, // 对于短的部分,再进行计算时候认为是0
int i= num1.length()-1; int j=num2.length()-1; int addFlag=0;
StringBuilder str=new StringBuilder();
while(i>=0 || j>=0 ){
int x= i>=0? num1.charAt(i)-'0':0; int y= j>=0? num2.charAt(j)-'0':0 ; int thisSum = x+y+addFlag; str.append(thisSum % 10); //
addFlag= thisSum/10; i--; j--; } // 最后两个字符串 都遍历完,最高位存在进位,则要记录下来 if(addFlag!=0){ str.append(addFlag); } str.reverse(); return str.toString(); }
}
复制代码


类似的算法题

 字符串相乘

class Solution {    public String multiply(String num1, String num2) {
// 示例 1234 * 567 其中1234是被乘数,567是乘数 if(num1.equals("0")|| num2.equals("0")) return "0";
String result=""; // 从乘数num2最后一位开始 逐位往左 与 被乘数num1 得到的结果 进行相加 for(int i=num2.length()-1;i>=0;i--){ int x=num2.charAt(i)-'0';
int countBit=0; StringBuilder thisLevelResult=new StringBuilder(); // 补0 最后一位不用补,倒数第二位要补一个0,倒数第三位要补2个0
for(int m=0; m<num2.length()-1-i; m++){ thisLevelResult.append("0"); }

// 计算 每一位 与被乘数的结果 for(int j=num1.length()-1; j>=0;j--){ int y= num1.charAt(j)-'0';
int thisResult= x*y+countBit;
thisLevelResult.append(thisResult%10); countBit=thisResult/10; }
if(countBit>0){ thisLevelResult.append(countBit); } result=addTwoNumStr(thisLevelResult.reverse().toString(),result.toString()); } return result;
}
public String addTwoNumStr(String num1, String num2){ if(num1.length()==0|| num1=="0"){ return num2; } if(num2.length()==0|| num2=="0"){ return num1; }
int i=num1.length()-1; int j=num2.length()-1; StringBuilder result=new StringBuilder(); int addBit=0; while(i>=0||j>=0){
int x= i>=0? num1.charAt(i)-'0':0; int y= j>=0? num2.charAt(j)-'0':0; int thisResult=x+y+addBit; result.append(thisResult%10); addBit=thisResult/10; i--; j--;
}
if(addBit>0){ result.append(addBit); } return result.reverse().toString(); }}
复制代码

Review

https://unixism.net/2019/04/linux-applications-performance-introduction/


文章对并发模型中 Linux 下网络 I/O 处理模型 进行性能测试

纵轴是并发连接数,横轴系统可以支持的最大 QPS(性能)




当并发连接数是 1000 的时候,可以看出 preforking、prethreaded、epoll 三种模式性能是相近的,也意味着 epoll 并不是在任何场景都具备相比其它模式的性能优势。


prethreaded 模式(作者源码中设置了 100 个线程)在 11000 并发的时候性能有 2200,但 12000 并发连接的时候,性能急剧下降到只有 970,推测是 12000 并发的时候触发了 C10K 问题,线程上下文切换的性能消耗超越了 IO 处理,成为了系统的处理瓶颈。


表格纵向比较时候,看数据变化较大的部分

  1. 创建进程的消耗是创建线程的消耗的 4 倍左右。

  2. 并发 2000 以内时,preforked、prethreaded、epoll 的性能相差无几,甚至 preforked 和 prethreaded 的性能有时候还稍微高一些。

这也是内部系统、中间件等并发数并不高的系统并不一定需要 epoll 的原因,用 preforked 和 prethreaded 模式能够达到相同的性能,并且实现要简单。

  1. 当并发数达到 8000 以上,只有 pthreaded 和 epoll 模式能够继续运行,但性能也有下降,epoll 的下降更加平稳一些。

  2. prethreaded 模式在 12000 并发连接的时候,性能急剧下降

  3. poll 模式随着并发数增多稳定下降,因为需要遍历的描述符越多,其性能越低。

  4. epoll 在并发数超过 10000 的时候性能开始下降,但下降比较平稳。不管并发连接数是多少个,从 epoll 的数据看,都是 2000+一点,也就是这个系统的 QPS 只能达到 2000+。


这个结论看起来比较简单,但是却隐含着一个关键的设计点:epoll 不是万能的,连接数太多的时候单进程 epoll 也是不行的。这也是为什么 Redis 可以用单进程 Reactor 模式,而 Nginx 必须用多进程 Reactor 模式,因为 Redis 的应用场景是内部访问,并发数一般不会超过 10000;而 Nginx 是互联网访问,并发数很容易超过 10000。

结合极客时间专栏看了一下


Tips

主题:excel 读写

  1. POI 方式

  • 引入依赖

<!-- excel工具 -->        <dependency>            <groupId>org.apache.poi</groupId>            <artifactId>poi-ooxml</artifactId>            <version>4.1.2</version>        </dependency>        <dependency>            <groupId>org.apache.poi</groupId>            <artifactId>poi-ooxml</artifactId>            <version>4.1.2</version>        </dependency>        <dependency>            <groupId>org.apache.poi</groupId>            <artifactId>poi-scratchpad</artifactId>            <version>4.1.2</version>        </dependency>
复制代码
  • 读工具

							List<Performance> processData = Lists.newArrayList();                InputStream dataInputStream = TestController.class.getResourceAsStream("/处理数据.xlsx");                // 读取整个Excel                XSSFWorkbook sheets = null;                try {                    sheets = new XSSFWorkbook(dataInputStream);                } catch (IOException e) {                    e.printStackTrace();                }                // 获取第一个表单Sheet                XSSFSheet sheetAt = sheets.getSheetAt(0);
//默认第一行为标题行,i = 0 XSSFRow titleRow = sheetAt.getRow(0); // 循环获取每一行数据 for (int i = 1; i < sheetAt.getPhysicalNumberOfRows(); i++) { XSSFRow row = sheetAt.getRow(i); // 读取每一格内容 StringBuilder sb = new StringBuilder(); for (int index = 0; index < row.getPhysicalNumberOfCells(); index++) { XSSFCell titleCell = titleRow.getCell(index); XSSFCell cell = row.getCell(index); cell.setCellType(CellType.STRING); if (cell.getStringCellValue().equals("")) { continue; } sb.append(cell); } System.out.println(i + "\t" + sb); }
复制代码


  1. 读大 excel 文件时候推荐使用

!-- 读取大量excel数据时使用 -->      <dependency>            <groupId>com.monitorjbl</groupId>            <artifactId>xlsx-streamer</artifactId>            <version>2.1.0</version>			</dependency>
复制代码


package com.platform.modules.admin.controller; import com.monitorjbl.xlsx.StreamingReader;import org.apache.poi.ss.usermodel.Cell;import org.apache.poi.ss.usermodel.Row;import org.apache.poi.ss.usermodel.Sheet;import org.apache.poi.ss.usermodel.Workbook; import java.io.File;import java.io.FileInputStream;import java.util.*;  public class ReadBigExcel {    public static Map<String, List<String>> test(File file) throws Exception{        FileInputStream in = new FileInputStream(file);        Map<String,List<String>> mapData = new HashMap<String, List<String>>();        Workbook wk = StreamingReader.builder()                .rowCacheSize(100)  //缓存到内存中的行数,默认是10                .bufferSize(4096)  //读取资源时,缓存到内存的字节大小,默认是1024                .open(in);  //打开资源,必须,可以是InputStream或者是File,注意:只能打开XLSX格式的文件        int sheetNums = wk.getNumberOfSheets();        for(int i = 0 ; i < sheetNums;i ++){            List<String> sheetData = new ArrayList<String>();            Sheet sheet = wk.getSheetAt(i);            String sheetName = wk.getSheetName(i);            //遍历所有的行            int k = 0;            for (Row row : sheet) {                StringBuilder sb = new StringBuilder();                //遍历所有的列                for (Cell cell : row) {                    sb.append(cell.getStringCellValue());                }                System.out.println(k++ + "\t" + sb.toString());            }          }        return mapData;    }     public static void main(String[] args) throws Exception {        File file = new File("C:\\Users\\Lenovo\\Desktop\\数据导入模板及填写格式 (2).xlsx");        long t1 = new Date().getTime();        test(file);        long t2 = new Date().getTime();         System.out.println((t2-t1)/1000 + "秒");     }}
复制代码


  1. EasyExcel

EasyExcel 是一个阿里出品的开源项目 ,看名字就能看出这个项目是为了让你更加简单的操作 Excel。另外 EasyExcel 还解决了 poi 内存溢出问题,修复了一些并发情况下一些 bug。

github 地址:https://github.com/alibaba/easyexcel

参考

http://t.zoukankan.com/edda-p-14191959.html

Share

最近在看左耳听风专栏,关于如何学习技术知识进行了总结


如何面对枯燥、大量的技术知识

  1. 要承认这个知识对我来说太高级了,目前没有找到切入点,不知道能用在哪

  2. 去找一下其应用场景,先从简单的应用学起(如何应用,适用场景),先从感性认识,再到理论基础学习

  3. 带着相关问题去学习,带着解决的东西学习,完成会有成就感(学习需要反馈,成就感才能持续)

  4. 总结学习知识并 分享学习心得、过程、笔记、代码,最好找到同伴(持续学习动力)

  5. 找牛人帮忙讲解指导也是好的选择


如何快速学习并掌握

  1. 找到关键路径,先学习主干知识,构建出关键路径,形成知识地图

  2. 认真阅读技术文档、用户手册

  3. 用不同的方式学习同一个东西(。比如:通过看书,听课,创建脑图,写博客,讲课,解决实际问题,等等。)

  4. 总结压缩信息,关注的是关键知识点。学习本质和原理的知识

  5. 用教的方式学习,学以致用,不强求记忆,找到方法,去推导知识或者答案

  6. 实践出真知坚持不懈


学习技术知识模版

  • 系统学习(学习阶段,多问自己为什么)


  1. 这个技术知识出现的背景是什么,它要达成什么样的目标,要解决的是什么问题

  2. 优点和缺点是什么,它为了解决问题 如何做了 tradeoff 取舍,带来哪些新的问题

  3. 适用场景有哪些(技术场景、业务场景)

  4. 技术的组成部分和关键点是什么,核心思想和核心组件是什么。 包含哪些关键技术点(找到关键路径,先学习主干知识,构建出关键路径,形成知识地图)

  5. 底层原理与关键实现

  6. 和已有的其他技术实现有什么区别(比如某个框架 或者存储技术)


  • 总结归纳(复习阶段,用自己的语言描述、输出)


把复杂问题用自己简单的语言进行描述,把我们学到的东西用自己的语言和理解重新组织并表达出来。 学习的开始阶段不急于总结,做结论。当对整个知识有了一定全面理解时候,在复习巩固的时候对知识进行回顾和重组会更好

要多看经典方法论图书,看别人如何总结归纳知识,可以进行模仿把自己学习的知识总结写出来,也可以写博客,或者讲给别人听,接收别人的批评与发奎


如何具有举一反三的能力

  1. 联想能力: 同一个事物不同的用法,其他相似或者相关的事物有哪些

  2. 抽象能力:解决问题的通用模型

  3. 自省能力:得到一个答案时候,站到自己的对立面找漏洞,获得全面的问题分析能力

在这方面,我对自己的训练如下。对于一个场景,制造出各种不同的问题或难题。对于一个问题,努力寻找尽可能多的解,并比较这些解的优劣。对于一个解,努力寻找各种不同的测试案例,以图让其健壮。


用户头像

苏籍

关注

还未添加个人签名 2019-01-30 加入

还未添加个人简介

评论

发布
暂无评论
ARTS打卡第7周_ARTS 打卡计划_苏籍_InfoQ写作社区