標籤: 台北網頁設計公司

  • Hibernate一對多、多對一的關係表達

    Hibernate一對多、多對一的關係表達

    一、關係表達:

    1、一對多、多對一表的關係:

    學生表:

     

     

      班級表:

     

     

     在學生表中,學生的學號是主鍵。在班級表中,班級號是主鍵,因此,學生表的外鍵是classno。因此,班級對應學生是一對多,學生對應班級是多對一。因為,一個班級可以有多個學生,但是一個學生只能在一個班級。

    2、對象的一對多、多對一關係:

    (1)在Class類中,定義Set集合,表達一對多的關係:

     

     

     

    package pers.zhb.domain;
    import java.util.HashSet;
    import java.util.Set;
    public class Class {
        private String classno;
        private String department;
        private String monitor;
        private String classname;
        private Set<Student> classes=new HashSet<Student>();//使用set集合表達一對多關係
        public Class(){
        }
        public Set<Student> getClasses() {
            return classes;
        }
        public void setClasses(Set<Student> classes) {
            this.classes = classes;
        }
        public String getMonitor() {
            return monitor;
        }
    
        public void setMonitor(String monitor) {
            this.monitor = monitor;
        }
    
        public String getDepartment() {
            return department;
        }
    
        public void setDepartment(String department) {
            this.department = department;
        }
    
    
    
        public String getClassname() {
            return classname;
        }
    
        public void setClassname(String classname) {
            this.classname = classname;
        }
        public String getClassno() {
            return classno;
        }
    
        public void setClassno(String classno) {
            this.classno = classno;
        }
        @Override
        public String toString() {
            return "Class{" +
                    "classno='" + classno + '\'' +
                    ", department='" + department + '\'' +
                    ", monitor='" + monitor + '\'' +
                    ", classname='" + classname + '\'' +
                    ", classes=" + classes +
                    '}';
        }
    }
    
    package pers.zhb.domain;
    public class Student {
        private Integer studentno;
        private String sname;
        private String sex;
        private String birthday;
        private String classno;
        private Float point;
        private String phone;
        private String email;
        private Clas aClas;
        public Student(){//無參的構造方法
        }
        public Clas getaClas() {
            return aClas;
        }
    
        public void setaClas(Clas aClas) {
            this.aClas = aClas;
        }
        @Override
        public String toString() {
            return "Student{" +
                    "studentno='" + studentno + '\'' +
                    ", sname='" + sname + '\'' +
                    ", sex='" + sex + '\'' +
                    ", birthday='" + birthday + '\'' +
                    ", classno='" + classno + '\'' +
                    ", point=" + point +
                    ", phone='" + phone + '\'' +
                    ", email='" + email + '\'' +
                    '}';
        }
    
        public int getStudentno() {
            return studentno;
        }
    
        public void setStudentno(int studentno) {
            this.studentno = studentno;
        }
    
        public String getSname() {
            return sname;
        }
    
        public void setSname(String sname) {
            this.sname = sname;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public String getBirthday() {
            return birthday;
        }
    
        public void setBirthday(String birthday) {
            this.birthday = birthday;
        }
    
        public String getClassno() {
            return classno;
        }
    
        public void setClassno(String classno) {
            this.classno = classno;
        }
    
        public float getPoint() {
            return point;
        }
    
        public void setPoint(float point) {
            this.point = point;
        }
    
        public String getPhone() {
            return phone;
        }
    
        public void setPhone(String phone) {
            this.phone = phone;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    }
    

      

      

    (2)定義學生和班級的關係:

     

     

     

    package pers.zhb.domain;
    import java.util.HashSet;
    import java.util.Set;
    public class Clas {
        private String classno;
        private String department;
        private String monitor;
        private String classname;
        private Set<Student> students=new HashSet<Student>();//使用set集合表達一對多關係
        public Clas(){
        }
        public Set<Student> getStudents() {
            return students;
        }
        public void setClasses(Set<Student> students) {
            this.students = students;
        }
        public String getMonitor() {
            return monitor;
        }
    
        public void setMonitor(String monitor) {
            this.monitor = monitor;
        }
    
        public String getDepartment() {
            return department;
        }
    
        public void setDepartment(String department) {
            this.department = department;
        }
    
    
    
        public String getClassname() {
            return classname;
        }
    
        public void setClassname(String classname) {
            this.classname = classname;
        }
        public String getClassno() {
            return classno;
        }
    
        public void setClassno(String classno) {
            this.classno = classno;
        }
        @Override
        public String toString() {
            return "Class{" +
                    "classno='" + classno + '\'' +
                    ", department='" + department + '\'' +
                    ", monitor='" + monitor + '\'' +
                    ", classname='" + classname + '\'' +
                    ",students=" + students +
                    '}';
        }
    }
    

      

    3、配置映射文件:

      Class.hbm.xml:

    (1)實現一對多的關係映射,即:一個班級對應多個學生:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="pers.zhb.domain">
        <class name="Clas" table="class">
            <id name="classno" column="classno">
                <generator class="native"></generator>
            </id><!--主鍵-->
            <property name="department" column="department"></property>
            <property name="monitor" column="monitor"></property>
            <property name="classname" column="classname"></property>
            <set name="students" table="student"><!--一對多關係配置-->
            <key column="classno" update="false"></key><!--指定了集合表的外鍵-->
                <one-to-many class="Student"></one-to-many>
            </set>
        </class>
    </hibernate-mapping>

     

    <set name="students">

    指定映射的存儲學生的集合的名字。

    <key column="classesno"></key>

    映射的class表的外鍵。

    <one-to-many class="Student"></one-to-many>

    指定學生的類型。

    (2)實現多對一的關係映射,即:多個學生對應一個班級。

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="pers.zhb.domain">
        <class name="Student" table="student">
            <id name="studentno" column="studentno" >
                <generator class="native"></generator>
            </id>
            <property name="birthday" column="birthday"></property>
            <property name="classno" column="classno" insert="false" update="false"></property>
            <property name="email" column="email"></property>
            <property name="phone" column="phone"></property>
            <property name="sex" column="sex"></property>
            <property name="sname" column="sname"></property>
            <property name="point" column="point"></property>
            <many-to-one name="aClas" column="classno" class="Clas"></many-to-one>
        </class>
    </hibernate-mapping>

     

    name屬性:映射的班級。

    column屬性:映射的班級對象對應的外鍵。

    class屬性:指定班級的類型。

    4、主配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-configuration PUBLIC
            "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
        <!--配置數據庫信息-必須的-->
        <session-factory>
            <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
            <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/stu_mangement</property>
            <property name="hibernate.connection.username">root</property>
            <property name="hibernate.connection.password">root</property>
            <!--配置hibernate信息-可選的-->
            <property name="hibernate.show_sql">true</property><!--輸出底層sql語句-->
            <property name="hibernate.format_sql">true</property><!--格式化輸出sql語句-->
            <property name="hibernate.hbm2ddl.auto">update</property><!--hibernate幫助創建表,如果已經有表更新表,如果沒有則創建新表-->
            <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
            <property name="hibernate.connection.isolation">4</property>
            <!--指定session與當前線程綁定-->
            <property name="hibernate.current_session_context_class">thread</property>
            <!--配置數據庫的方言,讓hibernate識別框架自己的特有語句-->
            <!--把映射文件放到核心配置文件-->
            <mapping resource="pers/zhb/domain/Student.hbm.xml"/><!--都在src目錄下-->
            <mapping resource="pers/zhb/domain/Class.hbm.xml"/><!--都在src目錄下-->
        </session-factory>
    </hibernate-configuration>
    

     二、具體運用:

    1、增加:

    (1)創建一個新班級併為新班級添加兩名學生:

    public class Test {
        public static void testSel() {
                Session session = HibernateUtils.openSession();//獲得session
                Transaction transaction = session.beginTransaction();//開啟事務
                Clas clas=new Clas();
                clas.setClassname("計科171");
                clas.setClassno(4600);
                clas.setDepartment("一號樓");
                clas.setMonitor("zhai");
    
                Student student=new Student();
                student.setSname("");
                student.setStudentno(2017151411);
                student.setPoint(123f);
                student.setSex("");
                student.setBirthday("2019-11-11");
                student.setPhone("18739496522");
                student.setClassno("221221");
                student.setEmail("34288334@qq.com");
    
                Student student1=new Student();
                student1.setSname("翟hb");
                student1.setStudentno(2017151419);
                student1.setPoint(666f);
                student1.setSex("");
                student1.setBirthday("2019-11-11");
                student1.setPhone("18739496522");
                student1.setClassno("221221");
                student1.setEmail("34288334@qq.com");
    
                clas.getStudents().add(student);//一對多,一個班級下有多個學生
                clas.getStudents().add(student1);//獲取Set集合對象並向其中添加元素
    
                student.setaClas(clas);//多對一,學生屬於哪一個班級
                student1.setaClas(clas);
    
                session.save(clas);
                session.save(student);
                session.save(student1);
    
                transaction.commit();//提交事務
                session.close();//關閉資源
            }

     

     (2)為一個已經存在的班級添加學生:

     public static void testAdd(){
                Session session = HibernateUtils.openSession();//獲得session
                Transaction transaction = session.beginTransaction();//開啟事務
                Clas clas=session.get(Clas.class,80501);//獲得一個已經存在的班級
                Student student=new Student();//創建一個學生對象
                student.setSname("翟zz");
                student.setStudentno(20190000);
                student.setPoint(133f);
                student.setSex("男");
                student.setBirthday("2019-11-16");
                student.setPhone("18739496522");
                student.setEmail("34288334@qq.com");
    
                Student student1=new Student();//再創建一個學生對象
                student1.setSname("翟zz");
                student1.setStudentno(20190000);
                student1.setPoint(133f);
                student1.setSex("男");
                student1.setBirthday("2019-11-16");
                student1.setPhone("18739496522");
                student1.setEmail("34288334@qq.com");
    
                clas.getStudents().add(student);//學生添加到班級
                student.setaClas(clas);//班級與學生對應
                clas.getStudents().add(student1);
                student1.setaClas(clas);
    
                session.save(student);
                session.save(student1);
    
    
                transaction.commit();//提交事務
                session.close();//關閉資源
    
            }
    

      

     

     2、刪除:

    刪除80501班的一名學生信息:

     public static void testDel() {
               Session session = HibernateUtils.openSession();//獲得session
               Transaction transaction = session.beginTransaction();//開啟事務
               Clas clas=session.get(Clas.class,80501);//獲得要刪除的學生屬於那一個班級
               Student student=session.get(Student.class,937221532);//獲得要刪除的學生
               clas.getStudents().remove(student);
               student.setaClas(null);
               transaction.commit();//提交事務
               session.close();//關閉資源
           }
    

     

     

     

     

     

     

     

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※帶您來看台北網站建置台北網頁設計,各種案例分享

    ※別再煩惱如何寫文案,掌握八大原則!

  • 自己實現 aop 和 spring aop

    說到,我們可以在 BeanPostProcessor 中對 bean 的初始化前化做手腳,當時也說了,我完全可以生成一個代理類丟回去。

    代理類肯定要為用戶做一些事情,不可能像學設計模式的時候創建個代理類,然後簡單的在前面打印一句話,後面打印一句話,這叫啥事啊,難怪當時聽不懂。最好是這個方法的前後過程可以自戶自己定義。

    小明說,這還不好辦,cglib 已經有現成的了,jdk 也可以實現動態代理,看 mybatis 其實也是這麼乾的,不然你想它一個接口怎麼就能找到 xml 的實現呢,可以參照下 mybatis 的代碼。

    所以首先學習下 cglib 和 jdk 的動態代理,我們來模擬下 mybatis 是如何通過接口來實現方法調用的

    cglib

    目標接口:

    public interface UserOperator {
        User queryUserByName(String name);
    }

    代理處理類:

    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class ProxyHandle implements MethodInterceptor{
        // 實現 MethodInterceptor 的代理攔截接口
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("獲取到 sqlId:"+method);
            System.out.println("獲取到執行參數列表:"+args[0]);
            System.out.println("解析 spel 表達式,並獲取到完整的 sql 語句");
            System.out.println("執行 sql ");
            System.out.println("結果集處理,並返回綁定對象");
            return new User("sanri",1);
        }
    }

    真正調用處:

    Enhancer enhancer = new Enhancer();
    
    enhancer.setSuperclass(UserOperator.class);
    enhancer.setCallback(new ProxyHandle());
    
    //可以把這個類添加進 ioc 容器,這就是真正的代理類
    UserOperator userOperator = (UserOperator) enhancer.create();
    
    User sanri = userOperator.queryByName("sanri");
    System.out.println(sanri);

    jdk

    import java.lang.reflect.InvocationHandler;
    public class ProxyHandler implements InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("獲取到 sqlId:"+method);
            System.out.println("獲取到執行參數列表:"+args[0]);
            System.out.println("解析 spel 表達式,並獲取到完整的 sql 語句");
            System.out.println("執行 sql ");
            System.out.println("結果集處理,並返回綁定對象");
            return new User("sanri",1);
        }
    }

    真正調用處:

    UserOperator proxyInstance = (UserOperator)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{UserOperator.class}, new ProxyHandler());
    User sanri = proxyInstance.queryByName("sanri");
    System.out.println(sanri);

    注:jdk 只能支持代理接口,但 cglib 是接口和實體類都可以代理; jdk 是使用實現接口方式,可以多實現,但 cglib 是繼承方式,也支持接口方式。

    代理模式和裝飾模式的區別:

    從這也可以看到代理模式和裝飾模式的區別 ,代理模式的方法簽名一般是不動的,但裝飾模式是為了方法的增強,一般會使用別的更好的方法來代替原方法。

    如何織入

    回到正文,這時我們已經可以創建一個代理類了,如何把用戶行為給弄進來呢,哎,又只能 回調 了,我們把現場信息給用戶,用戶實現我的接口,然後我找到接口的所有實現類進行順序調用,但這時候小明想到了幾個問題

    • 用戶不一定每個方法都要做代理邏輯,可能只是部分方法需要,我們應該能夠識別出是哪些方法需要做代理邏輯 (Pointcut)
    • 方法加代理邏輯的位置,方法執行前(Before),方法執行后(After),方法返回數據后(AfterReturning),方法出異常后(AfterThrowing),自定義執行(Around)

    根據單一職責原則,得寫五個接口,每個接口要包含 getPointCut() 方法和 handler() 方法,或者繞過單一職責原則,在一個接口中定義 6 個方法,用戶不想實現留空即可。總得來說,用戶只需要提交一份規則給我就行,這個規則你不管是用 json,xml ,或者 註解的方式,只要我能夠識別在 這個 pointcut 下,需要有哪些自定義行為,在另一個 pointcut 下又有哪些自定義行為即可。

    現拿到用戶行為了和切點了,還需要創建目標類的代理類,並把行為給綁定上去,在什麼時候創建代理類呢,肯定在把 bean 交給容器的時候悄悄的換掉啊, 說到 bean 有一個生命周期是用於做所有 bean 攔截的,並且可以在初始化前和初始化後進行攔截,沒錯,就是 BeanPostProcessor 我們可以在初始化後生成代理類。

    這裏需要注意,並不是所有類都需要創建代理。我們可以這樣檢測,讓 pointcut 提供一個方法用於匹配當前方法是否需要代理,當然這也是 pointcut 的職責,如果當前類有一個方法需要代理,那麼當前類是需要代理的,否則認為不需要代理,這麼做需要遍歷所有類的所有方法,如果運氣差的話,看上去很耗費性能 ,但 spring 也是這麼乾的。。。。。。優化的方案可以這麼玩,如果方法需要代理,在類上做一個標識,如果類上存在這個標識,則可以直接創建代理類。

    現在我們把用戶行為綁定到代理類,根據上面 jdk 動態代理和 cglib 動態代理的學習,我們發現,它們都有一個共同的傢伙,那就是方法攔截,用於攔截目標類的當前正在執行的方法,並增強其功能,我們可以在創建代理類的時候找到所有的用戶行為並按照順序和類型依次綁定,可以用責任鏈模式。

    看一下 spring 是怎麼玩的

    spring 也是在 BeanPostProcessor 接口的 postProcessAfterInitialization 生命周期進行攔截,具體的類為 AspectJAwareAdvisorAutoProxyCreator

    spring 配置切面有兩種方式,使用註解和使用配置,當然,現在流行註解的方式,更方便,但不管是配置還是註解,最後都會被解析成 Advisor(InstantiationModelAwarePointcutAdvisorImpl),spring 查找了所有實現 Advisor 的類,源代碼在 BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans

    advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);

    緊接着,spring 會使使用 Advisor 中的 pointcut 來看當前類是否需要創建代理類,跟進方法可以看到 canApply 方法中是遍歷了所有方法一個個匹配來看是否需要創建代理類的,如果有一個需要,則直接返回 true 。當然 spring 更嚴謹一些,它考慮到了可能有接口的方法需要有代理,我上面說在類加標識是不正確的。

    然後通過 createProxy 創建了代理類,裏面有區分 cglib 還是 aop ,下面單拿 cglib 來說

    CglibAopProxy.getProxy 中對類進行增強,主要看 Enhancer 類是如何設置的就好了,有一個 callback 參數 ,我們一般是第 0 個 callback 也即 DynamicAdvisedInterceptor 它是一個 cglib 的 MethodInterceptor

    它重寫的是 MethodInterceptor 的 intercept 方法,下面看這個方法,this.advised 是前面傳過來的用戶行為,getInterceptorsAndDynamicInterceptionAdviceAdvisor 適配成了 org.aopalliance.intercept.MethodInterceptor 分別對應切面的五種行為

    AbstractAspectJAdvice
      |- AspectJAfterReturningAdvice
      |- AspectJAfterAdvice implements org.aopalliance.intercept.MethodInterceptor
      |- AspectJAroundAdvice implements org.aopalliance.intercept.MethodInterceptor
      |- AspectJAfterThrowingAdvice implements org.aopalliance.intercept.MethodInterceptor
      |- AspectJMethodBeforeAdvice

    最後它封裝一個執行器,根據順序調用攔截器鏈,也即用戶行為列表,封裝執行的時候是強轉 org.aopalliance.intercept.MethodInterceptor 來執行的,但 AspectJAfterReturningAdviceAspectJMethodBeforeAdvice 沒有實現 org.aopalliance.intercept.MethodInterceptor 怎麼辦,所以 spring 在獲取用戶行為鏈的時候增加了一個適配器,專門用於把這兩種轉換成 MethodInterceptor

    其它說明

    • cglib 的 callback 只能寫一個,filter 用於選擇是第幾個 callback ,不要認為也是鏈式的

    • spring aop 中有比較多的設計模式,學設計模式的可以看下這塊的源碼 ,至少責任鏈,適配器,動態代理都可以在這看到
    • 切面類中如果有兩個一樣的行為,比如有兩個 @Before,排序規則為看方法名的 ascii 碼值,只測試過,並沒經過源碼,有興趣的可以自己去看一下。

    來個示例更容易理解

    我們除了使用 @Aspect 註解把切面規則告訴 spring 外,也可以學本身 aop 的實現,我們自己定義一個 Advisor ,因為 spring 就是掃描這個的,然後實現 pointcut 和 invoke 方法,一樣可以實現 aop 。

    聯繫上文: 我們來看看 spring 的 redis-cache 是如何做切面的

    文章說到,主要工作的類是 CacheInterceptor 它是一個 org.aopalliance.intercept.MethodInterceptor

    Advisor 是 BeanFactoryCacheOperationSourceAdvisor 也就是說創建代理類會掃描到這個類,最後執行會把其轉成 MethodInterceptor,因為它是一個 PointcutAdvisor ,查看 DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice 方法,第一個就是把 PointcutAdvisor 轉成 MethodInterceptor 繼續進入獲取攔截器的方法,可以知道就是獲取的 advice 屬性 CacheInterceptor

    一點小推廣

    創作不易,希望可以支持下我的開源軟件,及我的小工具,歡迎來 gitee 點星,fork ,提 bug 。

    Excel 通用導入導出,支持 Excel 公式
    博客地址:
    gitee:

    使用模板代碼 ,從數據庫生成代碼 ,及一些項目中經常可以用到的小工具
    博客地址:
    gitee:

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

  • 因應氣候變遷 財政部被賦要角

    文:易淇馨(烏特勒支大學國際海洋與環境法碩士生)

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

  • 聯合國氣候會議 環保署長與各國官員互動多

    摘錄自2019年12月13日中央社報導

    台灣不是巴黎氣候協定的締約國,仍積極參加聯合國氣候會議。代表台灣參與的環保署長張子敬表示,今年與各國官員的互動比往年多,不過,台灣減碳作為仍有不足的地方。

    聯合國氣候變化綱要公約(UNFCCC)第25次締約方會議(COP 25)2日至13日在西班牙首都馬德里舉行,外交部旗下的國際合作發展基金會、交通部中央氣象局、經濟部工業局、工業技術研究院、行政院農業委員會、媽媽監督核電廠聯盟等機關和團體利用會議期間在周邊會議發聲。

    張子敬在馬德里接受中央社記者訪問時表示,雖然無法進入大會會場,不過在場外與各國官員的互動比往年都多。除了邦交國,他也與歐盟、英國、瑞典、德國等國代表會晤,各國對台灣對抗氣候變遷的作法相當重視,台灣也樂於幫助需要幫助的國家。

    此外,張子敬還接受在地的「ABC日報」等媒體專訪,說明台灣的能源和減碳政策,以及為何因為中國的壓力,無法參與這次的氣候會議。

    張子敬表示,在減碳的作為上,台灣仍有許多不足之處。首先,台灣十分依賴進口化石能源,每度電的碳排量過高,住商、農業和交通部門的減碳都有待加強。

    其次,除了建立碳交易制度,落實總量管制,張子敬也支持徵收碳稅,「使用者付費本來就應該」。他說,環保署在水污染防治有許多經驗,未來碳稅的收入將專款專用,用來減少碳排。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※帶您來看台北網站建置台北網頁設計,各種案例分享

    ※別再煩惱如何寫文案,掌握八大原則!

  • 電動車推廣過於仰賴補助金?補助不明 1 月電動機車掛牌數下滑至 4.5%

    電動車推廣過於仰賴補助金?補助不明 1 月電動機車掛牌數下滑至 4.5%

    2020 年中央政府電動機車補助減少,加上各地方政府新年度補助尚未完全公布之下,1 月台灣機車總掛牌數量 46,211 輛當中,僅有 2,101 輛為電動機車。

    根據「中華電信數據所」的資料顯示,2020 年 1 月台灣機車市場掛牌總數當中,44,110 輛為燃油車,電動車則為 2,101 輛,油車與電車的銷售比為 95.5%:4.5%。2019 年 12 月電動機車掛牌量達到創紀錄的 28,701 輛,占整體機車掛牌量的 26.83%。

    相較於 2019 年屢創高峰的氣勢,2020 年 1 月電動機車的銷量下滑不少。原因基本上可以歸咎於三點,首先是中央電動機車補助減少,環保署補助完全退場,工業局補助則減少 3,000 元。雖然會有環保署汰舊換新補助補位,但新購電動機車補助還是會受到影響。

    2020 年 1 月機車市場中燃油機車占 95.5%,電動機車僅占 4.5%。

    其次則是消費者的預期心理,由於 2020 年補助金額降低,因此有興趣的消費者會選擇提前在 2019 年底購買。雖然創造了 2019 年 11 月和 12 月的銷售高峰,但 2020 年的銷量也提早兌現。

    第三是各縣市補助辦法尚未明朗,截至過年前僅有 8 個縣市公布電動機車補助方案。其中台北市、彰化和屏東跟隨中央政策,不再補助新購電動機車,其他縣市則調降補助金額或維持不變,汰舊換新補助各縣市也有幅度不等的減少。但包括新北市和高雄市兩個電動機車銷售重鎮都尚未公布,因此這些縣市應該有不少消費者保持觀望。

    多數縣市尚未公告 2020 年電動機車補助,公告的大多有幅度不一的減少。

    光陽(Kymco)執行長柯俊斌認為,1 月電動機車市場仍極度仰賴補助,地方政府補助辦法尚未全面公告,因此銷售仍不見起色。由於電動機車銷量減少的影響,以及農曆春節連續假期,整體機車市場也較上個月衰退。此外,雖然新型冠狀病毒疫情廣受關注,不過對機車銷量的衝擊尚不明顯,有待進一步觀察。

    (合作媒體:。圖片來源:光陽)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

  • 2016第二屆亞太新能源汽車國際峰會:聚焦汽車智能化,網聯化,輕量化和電氣化技術融合

    2016第二屆亞太新能源汽車國際峰會:聚焦汽車智能化,網聯化,輕量化和電氣化技術融合

    由中國汽車工程研究院、英納威-俄羅斯聖彼德堡國立技術大學中俄功能材料新能源技術研究院支援,上海領研商務諮詢有限公司主辦「2016 第二屆 亞太新能源汽車國際峰會」於6月2-3日在北京萬豪酒店隆重召開,來自相關政府部門、整車企業、行業機構、新能源汽車關鍵零部件供應商,智慧網聯汽車關鍵零部件企業,先進輕量化材料及解決方案企業,諮詢公司,工程開發公司,檢測認證機構,高校科研院所及投資公司等150余名行業代表蒞臨現場,分享交流新能源汽車產業政策及未來發展趨勢、新能源汽車動力總成及輕量化技術、整車集成及動力電池技術、先進智慧網聯及無線充電技術等。

    2016ANEVS會議現場

    第一天上午來自權威行業機構,知名諮詢公司及整車廠的發言嘉賓和大家分享了新能源汽車產業政策及未來發展趨勢:

    中國內燃機工業協會副秘書長魏安力以應對第四階段乘用車油耗法規的節能技術路線分析,在分析國家能源安全及大氣污染控制的背景下,闡述了現階段混合動力技術是當前國內汽車節能減排的最佳技術路徑選擇。

    貝恩公司的全球合夥人戴加輝先生,就全球新能源汽車市場發展趨勢和挑戰發表了精彩的演講,重點介紹了國內外汽車電氣化發展中存在的挑戰,純電動和插電式混合動力及動力電池發展現狀及趨勢等。

    來自北汽集團的新能源汽車管理部部長詹文章博士以北汽集團新能源汽車發展戰略和實踐發表主題演講,分享了北汽集團未來新能源汽車發展技術和戰略規劃以及電氣化和智慧網聯及輕量化技術融合發展趨勢。

    吉利汽車研究院總工程師熊飛博士,就新能源汽車輕量化技術開發與落地發表演講,重點介紹了應用于吉利新能源汽車的先進輕量化技術及未來發展規劃。

    特斯拉汽車中國區公共政策與充電基礎設施總監的高翔先生,就高性能智慧互聯電動汽車-清潔交通的革新發表演講,著重闡述了特斯拉汽車在電氣化和智慧互聯技術融合方面的發展經驗。

    來自奇瑞汽車的副總裁兼動力總成技術中心執行總監韓爾樑先生,就最有競爭力的奇瑞動力系統研發發表主題演講,和大家分享了奇瑞未來新能源汽車動力系統發展規劃,特別重點宣導發展燃料電池汽車的研發和技術儲備。

    德國國際合作機構的Markus Wagner先生,就電動交通和可再生能源在德國的能源經濟型效應及發展現狀發表演講,介紹了德國在可再生能源和電動交通協同發展的經驗。

    來自羅蘭貝格的高級項目經理鄭贇先生就全球智慧網聯汽車市場發展趨勢和挑戰發表演講,系統介紹了國內外智慧網聯汽車的發展現狀和存在的挑戰,還特別介紹了羅蘭貝格關於汽車電氣化和輕量化技術融合發展的最新研究成果。

    第二天,針對汽車電氣化和智慧化,網聯化及智慧化技術融合,會議的部分演講嘉賓介紹了最新的技術解決方案:

    來自吉凱恩傳動系統的中國區工程技術支援總監克裡澌汀·高熙先生,就應用於新能源汽車的先進變速器技術發表演講,重點介紹和展示了應用于寶馬、三菱、富豪及保時捷等新能源汽車的變速器和傳動系統解決方案。

    來自能啟能電子的技術總監徐向陽先生,就新能源汽車火情預警及控制策略發表演講,重點介紹和展示了他們目前所做的對新能源汽車電池熱失控的早期預警、智慧判斷、提前干預和主動滅火等研究。

    來自諾貝麗斯的中國區董事總經理劉清先生,就全鋁車身在新能源汽車中輕量化應用的最新發展發表演講,重點介紹了全鋁車身對於新能源汽車的重要性及全鋁車身汽車的閉合循環系統。

    來自東軟睿馳的副總經理曹斌先生,就新能源汽車動力電池安全方面的思考及研發發表演講,重點介紹了PACK電池包、BMS電池管理系統及ICS等在新能源汽車的應用及安全的解決方案。

    來自地平線機器人科技的業務拓展總監李星宇先生,就深度學習為自動駕駛帶來的全新突破發表演講,重點介紹了自動駕駛的演算法、晶片、系統集成三方面。

     

    更多關於發言嘉賓詳細演講資料,請關注微信公眾號:領研GIIAutomotive

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※帶您來看台北網站建置台北網頁設計,各種案例分享

    ※別再煩惱如何寫文案,掌握八大原則!

  • Gogoro積極搶市,南臺灣首站小琉球

    Gogoro積極搶市,南臺灣首站小琉球

    台灣本土電動機車品牌Gogoro又展開新動作!Gogoro與遠傳電信合作,推出申辦門號即享購車折扣的優惠,未來還將建立更廣泛的物聯網(IoT)功能。同時,Gogoro也正式走入南台灣,首個佈點將位於離島小琉球。

    搶市,Gogoro與通訊業者合作

    Gogoro日前宣布與遠傳電信合作推出「超級騎機」優惠購車方案,從5月13日起,凡到Gogoro門市申辦特定遠傳電信方案,就享有最高新台幣2萬元的購車優惠。若加上政府對民眾換購電動載具所提出的補貼,Gogoro最低只要新台幣4.3萬元就能騎回家,比目前主流的汽油機車還便宜。

    Gogoro表示,未來將與遠傳合作推動更多IoT服務,強化「智慧城市」與「量身打造」功能。

    此外,Gogoro為了替客戶降低使用成本,還將推出購車送免費里程1,200公里、電池租金低資費方案等服務,電池每月最低租金599元,可行駛400公里,超過後每1公里1元新台幣,積極搶市。

    台灣另一家電動機車業者中華汽車也大力推動e-moving車款,直接刺激台灣市場需求。目前,台灣每月電動機車銷量已達1,200輛左右,占整體機車銷售量2%以上。

    Gogoro登上小琉球島!

    成功在大台北、桃園、新竹等北台灣縣市佈點後,Gogoro進軍南台灣的第一站,被直擊將登陸離島小琉球。報導指出,小琉球去年底結束一間電動機車公司的合約,空出約300輛機車的需求缺口;有業者看上此一商機,因此與Gogoro商議,協助Gogoro南進,初期先引入100輛電動車試水溫。

    相較於舊款電動機車,Gogoro的馬力、續航力更好。且小琉球空間不大,設置一座24小時運作的電池交換站就很足夠。

    (照片來源:Gogoro Taiwan 臉書專頁)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

  • 特斯拉第 2 季淨損擴大 二度下修銷售預測

    美國電動車大廠特斯拉(Tesla)公佈第 2 季財報,凈虧損為 1.843 億美元,而因車輛銷售持續攀高,營收成長 24%,達到 9.55 億美元,但與去年同期的凈虧損 1.542 億美元相比有所擴大,且一年內第二度下修銷售預測。   特斯拉表示,今年交車目標為 5 萬至 5.5 萬輛之間。去年執行長穆斯克發下豪語,說今年的銷售量將達 6 萬輛,今年稍早已調降到 5.5 萬輛,如今再度下修。不過,特斯拉仍預期今年 9 月底這款車將開始「少量交車」,但進度就算只延後一周,整體產量就會減少約 800 輛。     特斯拉上季資本支出總計 4.052 億美元,主要是持續用在 Model X 新車,以及預定 2016 年開幕的內華達州電池新廠。今年上半年的總支出達 8.312 億美元,預估全年支出約為 15 億美元。經調整後特斯拉上季每股虧損 48 美分,優於分析師預估的每股虧損 60 美分,去年同期則是每股獲利 13 美分。         

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※帶您來看台北網站建置台北網頁設計,各種案例分享

    ※別再煩惱如何寫文案,掌握八大原則!

  • 有了四步解題法模板,再也不害怕動態規劃!(看不懂算我輸)

    有了四步解題法模板,再也不害怕動態規劃!(看不懂算我輸)

    導言

    動態規劃問題一直是算法面試當中的重點和難點,並且動態規劃這種通過空間換取時間的算法思想在實際的工作中也會被頻繁用到,這篇文章的目的主要是解釋清楚 什麼是動態規劃,還有就是面對一道動態規劃問題,一般的 思考步驟 以及其中的注意事項等等,最後通過幾道題目將理論和實踐結合。

    什麼是動態規劃

    如果你還沒有聽說過動態規劃,或者僅僅只有耳聞,或許你可以看看 Quora 上面的這個 回答

    How to explain dynamic

    用一句話解釋動態規劃就是 “記住你之前做過的事”,如果更準確些,其實是 “記住你之前得到的答案”。

    我舉個大家工作中經常遇到的例子。

    在軟件開發中,大家經常會遇到一些系統配置的問題,配置不對,系統就會報錯,這個時候一般都會去 Google 或者是查閱相關的文檔,花了一定的時間將配置修改好。

    過了一段時間,去到另一個系統,遇到類似的問題,這個時候已經記不清之前修改過的配置文件長什麼樣,這個時候有兩種方案,一種方案還是去 Google 或者查閱文檔,另一種方案是借鑒之前修改過的配置,第一種做法其實是萬金油,因為你遇到的任何問題其實都可以去 Google,去查閱相關文件找答案,但是這會花費一定的時間,相比之下,第二種方案肯定會更加地節約時間,但是這個方案是有條件的,條件如下:

    • 之前的問題和當前的問題有着關聯性,換句話說,之前問題得到的答案可以幫助解決當前問題
    • 需要記錄之前問題的答案

    當然在這個例子中,可以看到的是,上面這兩個條件均滿足,大可去到之前配置過的文件中,將配置拷貝過來,然後做些細微的調整即可解決當前問題,節約了大量的時間。

    不知道你是否從這些描述中發現,對於一個動態規劃問題,我們只需要從兩個方面考慮,那就是 找出問題之間的聯繫,以及 記錄答案,這裏的難點其實是找出問題之間的聯繫,記錄答案只是順帶的事情,利用一些簡單的數據結構就可以做到。

    概念

    上面的解釋如果大家可以理解的話,接

      動態規劃算法是通過拆分問題,定義問題狀態和狀態之間的關係,使得問題能夠以遞推(或者說分治)的方式去解決。它的幾個重要概念如下所述。

      階段:對於一個完整的問題過程,適當的切分為若干個相互聯繫的子問題,每次在求解一個子問題,則對應一個階段,整個問題的求解轉化為按照階段次序去求解。

      狀態:狀態表示每個階段開始時所處的客觀條件,即在求解子問題時的已知條件。狀態描述了研究的問題過程中的狀況。

      決策:決策表示當求解過程處於某一階段的某一狀態時,可以根據當前條件作出不同的選擇,從而確定下一個階段的狀態,這種選擇稱為決策。

      策略:由所有階段的決策組成的決策序列稱為全過程策略,簡稱策略。

      最優策略:在所有的策略中,找到代價最小,性能最優的策略,此策略稱為最優策略。

      狀態轉移方程:狀態轉移方程是確定兩個相鄰階段狀態的演變過程,描述了狀態之間是如何演變的。

    思考動態規劃問題的四個步驟

    一般解決動態規劃問題,分為四個步驟,分別是

    • 問題拆解,找到問題之間的具體聯繫
    • 狀態定義
    • 遞推方程推導
    • 實現

    這裏面的重點其實是前兩個,如果前兩個步驟順利完成,後面的遞推方程推導和代碼實現會變得非常簡單。

    這裏還是拿 Quora 上面的例子來講解,“1+1+1+1+1+1+1+1” 得出答案是 8,那麼如何快速計算 “1+ 1+1+1+1+1+1+1+1”,我們首先可以對這個大的問題進行拆解,這裏我說的大問題是 9 個 1 相加,這個問題可以拆解成 1 + “8 個 1 相加的答案”,8 個 1 相加繼續拆,可以拆解成 1 + “7 個 1 相加的答案”,… 1 + “0 個 1 相加的答案”,到這裏,第一個步驟 已經完成。

    狀態定義 其實是需要思考在解決一個問題的時候我們做了什麼事情,然後得出了什麼樣的答案,對於這個問題,當前問題的答案就是當前的狀態,基於上面的問題拆解,你可以發現兩個相鄰的問題的聯繫其實是 后一個問題的答案 = 前一個問題的答案 + 1,這裏,狀態的每次變化就是 +1。

    定義好了狀態,遞推方程就變得非常簡單,就是 dp[i] = dp[i - 1] + 1,這裏的 dp[i] 記錄的是當前問題的答案,也就是當前的狀態,dp[i - 1] 記錄的是之前相鄰的問題的答案,也就是之前的狀態,它們之間通過 +1 來實現狀態的變更。

    最後一步就是實現了,有了狀態表示和遞推方程,實現這一步上需要重點考慮的其實是初始化,就是用什麼樣的數據結構,根據問題的要求需要做那些初始值的設定。

    public int dpExample(int n) {
        int[] dp = new int[n + 1];  // 多開一位用來存放 0 個 1 相加的結果

        dp[0] = 0;      // 0 個 1 相加等於 0

        for (int i = 1; i <= n; ++i) {
            dp[i] = dp[i - 1] + 1;
        }

        return dp[n];
    }

    你可以看到,動態規劃這四個步驟其實是相互遞進的,狀態的定義離不開問題的拆解,遞推方程的推導離不開狀態的定義,最後的實現代碼的核心其實就是遞推方程,這中間如果有一個步驟卡殼了則會導致問題無法解決,當問題的複雜程度增加的時候,這裏面的思維複雜程度會上升。

    接下來我們再來看看 LeetCode 上面的幾道題目,通過題目再來走一下這些個分析步驟。

    題目實戰

    爬樓梯

    但凡涉及到動態規劃的題目都離不開一道例題:爬樓梯(LeetCode 第 70 號問題)。

    題目描述

    假設你正在爬樓梯。需要 n 階你才能到達樓頂。

    每次你可以爬 1 或 2 個台階。你有多少種不同的方法可以爬到樓頂呢?

    注意:給定 n 是一個正整數。

    示例 1:

    輸入: 2
    輸出: 2
    解釋: 有兩種方法可以爬到樓頂。

    1. 1 階 + 1 階
    2. 2 階

    示例 2:

    輸入: 3
    輸出: 3
    解釋: 有三種方法可以爬到樓頂。

    1. 1 階 + 1 階 + 1 階
    2. 1 階 + 2 階
    3. 2 階 + 1 階

    題目解析

    爬樓梯,可以爬一步也可以爬兩步,問有多少種不同的方式到達終點,我們按照上面提到的四個步驟進行分析:

    • 問題拆解:

      我們到達第 n 個樓梯可以從第 n – 1 個樓梯和第 n – 2 個樓梯到達,因此第 n 個問題可以拆解成第 n – 1 個問題和第 n – 2 個問題,第 n – 1 個問題和第 n – 2 個問題又可以繼續往下拆,直到第 0 個問題,也就是第 0 個樓梯 (起點)

    • 狀態定義

      “問題拆解” 中已經提到了,第 n 個樓梯會和第 n – 1 和第 n – 2 個樓梯有關聯,那麼具體的聯繫是什麼呢?你可以這樣思考,第 n – 1 個問題裏面的答案其實是從起點到達第 n – 1 個樓梯的路徑總數,n – 2 同理,從第 n – 1 個樓梯可以到達第 n 個樓梯,從第 n – 2 也可以,並且路徑沒有重複,因此我們可以把第 i 個狀態定義為 “從起點到達第 i 個樓梯的路徑總數”,狀態之間的聯繫其實是相加的關係。

    • 遞推方程

      “狀態定義” 中我們已經定義好了狀態,也知道第 i 個狀態可以由第 i – 1 個狀態和第 i – 2 個狀態通過相加得到,因此遞推方程就出來了 dp[i] = dp[i - 1] + dp[i - 2]

    • 實現

      你其實可以從遞推方程看到,我們需要有一個初始值來方便我們計算,起始位置不需要移動 dp[0] = 0,第 1 層樓梯只能從起始位置到達,因此 dp[1] = 1,第 2 層樓梯可以從起始位置和第 1 層樓梯到達,因此 dp[2] = 2,有了這些初始值,後面就可以通過這幾個初始值進行遞推得到。

    參考代碼

    public int climbStairs(int n) {
        if (n == 1) {
            return 1;
        }

        int[] dp = new int[n + 1];  // 多開一位,考慮起始位置

        dp[0] = 0; dp[1] = 1; dp[2] = 2;
        for (int i = 3; i <= n; ++i) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }

        return dp[n];
    }

    三角形最小路徑和

    LeetCode 第 120 號問題:三角形最小路徑和。

    題目描述

    給定一個三角形,找出自頂向下的最小路徑和。每一步只能移動到下一行中相鄰的結點上。

    例如,給定三角形:

    [
         [2],
        [3,4],
       [6,5,7],
      [4,1,8,3]
    ]

    自頂向下的最小路徑和為 11(即,2 + 3 + 5 + 1 = 11)。

    說明:

    如果你可以只使用 O(n) 的額外空間(n 為三角形的總行數)來解決這個問題,那麼你的算法會很加分。

    題目解析

    給定一個三角形數組,需要求出從上到下的最小路徑和,也和之前一樣,按照四個步驟來分析:

    • 問題拆解:

      這裏的總問題是求出最小的路徑和,路徑是這裏的分析重點,路徑是由一個個元素組成的,和之前爬樓梯那道題目類似,[i][j] 位置的元素,經過這個元素的路徑肯定也會經過 [i - 1][j] 或者 [i - 1][j - 1],因此經過一個元素的路徑和可以通過這個元素上面的一個或者兩個元素的路徑和得到。

    • 狀態定義

      狀態的定義一般會和問題需要求解的答案聯繫在一起,這裏其實有兩種方式,一種是考慮路徑從上到下,另外一種是考慮路徑從下到上,因為元素的值是不變的,所以路徑的方向不同也不會影響最後求得的路徑和,如果是從上到下,你會發現,在考慮下面元素的時候,起始元素的路徑只會從[i - 1][j] 獲得,每行當中的最後一個元素的路徑只會從 [i - 1][j - 1] 獲得,中間二者都可,這樣不太好實現,因此這裏考慮從下到上的方式,狀態的定義就變成了 “最後一行元素到當前元素的最小路徑和”,對於 [0][0] 這個元素來說,最後狀態表示的就是我們的最終答案。

    • 遞推方程

      “狀態定義” 中我們已經定義好了狀態,遞推方程就出來了

      dp[i][j] = Math.min(dp[i + 1][j], dp[i + 1][j + 1]) + triangle[i][j]
    • 實現

      這裏初始化時,我們需要將最後一行的元素填入狀態數組中,然後就是按照前面分析的策略,從下到上計算即可

    參考代碼

    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();

        int[][] dp = new int[n][n];

        List<Integer> lastRow = triangle.get(n - 1);

        for (int i = 0; i < n; ++i) {
            dp[n - 1][i] = lastRow.get(i);
        }

        for (int i = n - 2; i >= 0; --i) {
            List<Integer> row = triangle.get(i);
            for (int j = 0; j < i + 1; ++j) {
                dp[i][j] = Math.min(dp[i + 1][j], dp[i + 1][j + 1]) + row.get(j);
            }
        }

        return dp[0][0];
    }

    最大子序和

    LeetCode 第 53 號問題:最大子序和。

    題目描述

    給定一個整數數組 nums ,找到一個具有最大和的連續子數組(子數組最少包含一個元素),返回其最大和。

    示例:

    輸入: [-2,1,-3,4,-1,2,1,-5,4],
    輸出: 6
    解釋: 連續子數組 [4,-1,2,1] 的和最大,為 6。

    進階:

    如果你已經實現複雜度為 O(n) 的解法,嘗試使用更為精妙的分治法求解。

    題目解析

    求最大子數組和,非常經典的一道題目,這道題目有很多種不同的做法,而且很多算法思想都可以在這道題目上面體現出來,比如動態規劃、貪心、分治,還有一些技巧性的東西,比如前綴和數組,這裏還是使用動態規劃的思想來解題,套路還是之前的四步驟:

    • 問題拆解:

      問題的核心是子數組,子數組可以看作是一段區間,因此可以由起始點和終止點確定一個子數組,兩個點中,我們先確定一個點,然後去找另一個點,比如說,如果我們確定一個子數組的截止元素在 i 這個位置,這個時候我們需要思考的問題是 “以 i 結尾的所有子數組中,和最大的是多少?”,然後我們去試着拆解,這裏其實只有兩種情況:

    • i 這個位置的元素自成一個子數組

    • i 位置的元素的值 + 以 i – 1 結尾的所有子數組中的子數組和最大的值

      你可以看到,我們把第 i 個問題拆成了第 i – 1 個問題,之間的聯繫也變得清晰

    • 狀態定義

      通過上面的分析,其實狀態已經有了,dp[i] 就是 “以 i 結尾的所有子數組的最大值

    • 遞推方程

      拆解問題的時候也提到了,有兩種情況,即當前元素自成一個子數組,另外可以考慮前一個狀態的答案,於是就有了

      dp[i] = Math.max(dp[i - 1] + array[i], array[i])

      化簡一下就成了:

      dp[i] = Math.max(dp[i - 1], 0) + array[i]
    • 實現

      題目要求子數組不能為空,因此一開始需要初始化,也就是 dp[0] = array[0],保證最後答案的可靠性,另外我們需要用一個變量記錄最後的答案,因為子數組有可能以數組中任意一個元素結尾

    參考代碼

    public int maxSubArray(int[] nums{
        if (nums == null || nums.length == 0) {
            return 0;
        }

        int n = nums.length;

        int[] dp = new int[n];

        dp[0] = nums[0];

        int result = dp[0];

        for (int i = 1; i < n; ++i) {
            dp[i] = Math.max(dp[i - 1], 0) + nums[i];
            result = Math.max(result, dp[i]);
        }

        return result;
    }

    總結

    通過這幾個簡單的例子,相信你不難發現,解動態規劃題目其實就是拆解問題,定義狀態的過程,嚴格說來,動態規劃並不是一個具體的算法,而是凌駕於算法之上的一種 思想

    這種思想強調的是從局部最優解通過一定的策略推得全局最優解,從子問題的答案一步步推出整個問題的答案,並且利用空間換取時間。從很多算法之中你都可以看到動態規劃的影子,所以,還是那句話 技術都是相通的,找到背後的本質思想是關鍵

    公眾號:五分鐘學算法(ID:CXYxiaowu)
    博客:www.cxyxiaowu.com(目前更新了 500 篇算法文章,歡迎訪問學習)
    知乎:程序員吳師兄
    一個正在學習算法的人,致力於將算法講清楚​!

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

  • Android音頻開發(1):基礎知識

    Android音頻開發(1):基礎知識

    Android音頻開發(1):基礎知識

    導讀

    人的說話頻率基本上為300Hz~3400Hz,但是人耳朵聽覺頻率基本上為20Hz~20000Hz。

    對於人類的語音信號而言,實際處理一般經過以下步驟:

    人嘴說話——>聲電轉換——>抽樣(模數轉換)——>量化(將数字信號用適當的數值表示)——>編碼(數據壓縮)——>

    傳輸(網絡或者其他方式)

    ——> 解碼(數據還原)——>反抽樣(數模轉換)——>電聲轉換——>人耳聽聲。

    • 抽樣率

    實際中,人發出的聲音信號為模擬信號,想要在實際中處理必須為数字信號,即採用抽樣、量化、編碼的處理方案。

    處理的第一步為抽樣,即模數轉換。

    簡單地說就是通過波形採樣的方法記錄1秒鐘長度的聲音,需要多少個數據。

    根據奈魁斯特(NYQUIST)採樣定理,用兩倍於一個正弦波的頻繁率進行採樣就能完全真實地還原該波形。

    所以,對於聲音信號而言,要想對離散信號進行還原,必須將抽樣頻率定為40KHz以上。實際中,一般定為44.1KHz。

    44.1KHz採樣率的聲音就是要花費44000個數據來描述1秒鐘的聲音波形。

    原則上採樣率越高,聲音的質量越好,採樣頻率一般共分為22.05KHz、44.1KHz、48KHz三個等級。

    22.05 KHz只能達到FM廣播的聲音品質,44.1KHz則是理論上的CD音質界限,48KHz則已達到DVD音質了。

    • 碼率

    對於音頻信號而言,實際上必須進行編碼。在這裏,編碼指信源編碼,即數據壓縮。如果,未經過數據壓縮,直接量化進行傳輸則被稱為PCM(脈衝編碼調製)。
    要算一個PCM音頻流的碼率是一件很輕鬆的事情,採樣率值×採樣大小值×聲道數 bps。
    一個採樣率為44.1KHz,採樣大小為16bit,雙聲道的PCM編碼的WAV文件,它的數據速率則為 44.1K×16×2 =1411.2 Kbps。
    我們常說128K的MP3,對應的WAV的參數,就是這個1411.2 Kbps,這個參數也被稱為數據帶寬,它和ADSL中的帶寬是一個概念。將碼率除以8,就可以得到這個WAV的數據速率,即176.4KB/s。

    這表示存儲一秒鐘採樣率為44.1KHz,採樣大小為16bit,雙聲道的PCM編碼的音頻信號,需要176.4KB的空間,1分鐘則約為10.34M,這對大部分用戶是不可接受的,尤其是喜歡在電腦上聽音樂的朋友,要降低磁盤佔用

    只有2種方法,降低採樣指標或者壓縮。降低指標是不可取的,因此專家們研發了各種壓縮方案。最原始的有DPCM、ADPCM,其中最出名的為MP3。

    所以,採用了數據壓縮以後的碼率遠小於原始碼率。

    一、發的主要應用有哪些?

    音頻播放器,錄音機,語音電話,音視頻監控應用,音視頻直播應用,音頻編輯/處理軟件,藍牙耳機/音箱,等等。

    二、頻開發的具體內容有哪些?

    (1)音頻採集/播放

    (2)音頻算法處理(去噪、靜音檢測、回聲消除、音效處理、功放/增強、混音/分離,等等)

    (3)音頻的編解碼和格式轉換

    (4)音頻傳輸協議的開發(SIP,A2DP、AVRCP,等等)

    三、 音頻應用的難點在哪?

    延時敏感、卡頓敏感、噪聲抑制(Denoise)、回聲消除(AEC)、靜音檢測(VAD)、混音算法,等等。

    四、 音頻開發基礎概念有哪些?

    在音頻開發中,下面的這幾個概念經常會遇到。

    1. 採樣率(samplerate)

    採樣就是把模擬信號数字化的過程,不僅僅是音頻需要採樣,所有的模擬信號都需要通過採樣轉換為可以用0101來表示的数字信號,示意圖如下所示:

    藍色代表模擬音頻信號,紅色的點代表採樣得到的量化數值。

    採樣頻率越高,紅色的間隔就越密集,記錄這一段音頻信號所用的數據量就越大,同時音頻質量也就越高。

    根據奈奎斯特理論,採樣頻率只要不低於音頻信號最高頻率的兩倍,就可以無損失地還原原始的聲音。

    通常人耳能聽到頻率範圍大約在20Hz~20kHz之間的聲音,為了保證聲音不失真,採樣頻率應在40kHz以上。常用的音頻採樣頻率有:8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz、96kHz、192kHz等。

    對採樣率為44.1kHz的AAC音頻進行解碼時,一幀的解碼時間須控制在23.22毫秒內。

    通常是按1024個採樣點一幀

    分析:

    1. AAC

    一個AAC原始幀包含某段時間內1024個採樣點相關數據。

    用1024主要是因為AAC是用的1024點的mdct。

    音頻幀的播放時間=一個AAC幀對應的採樣樣本的個數/採樣頻率(單位為s)

    採樣率(samplerate)為 44100Hz,表示每秒 44100個採樣點,

    所以,根據公式,

    音頻幀的播放時長 = 一個AAC幀對應的採樣點個數 / 採樣頻率

    則,當前一幀的播放時間 = 1024 * 1000/44100= 23.22 ms(單位為ms)

    48kHz採樣率,

    則,當前一幀的播放時間 = 1024 * 1000/48000= 21.333ms(單位為ms)

    22.05kHz採樣率,

    則,當前一幀的播放時間 = 1024 * 1000/22050= 46.439ms(單位為ms)

    2. MP3

    mp3 每幀均為1152個字節,

    則:

    每幀播放時長 = 1152 * 1000 / sample_rate

    例如:sample_rate = 44100HZ時,

    計算出的時長為26.122ms,

    這就是經常聽到的mp3每幀播放時間固定為26ms的由來。

    2. 量化精度(位寬)

    上圖中,每一個紅色的採樣點,都需要用一個數值來表示大小,這個數值的數據類型大小可以是:4bit、8bit、16bit、32bit等等,位數越多,表示得就越精細,聲音質量自然就越好,當然,數據量也會成倍增大。

    常見的位寬是:8bit 或者 16bit

    3. 聲道數(channels)

    由於音頻的採集和播放是可以疊加的,因此,可以同時從多個音頻源採集聲音,並分別輸出到不同的揚聲器,故聲道數一般表示聲音錄製時的音源數量或回放時相應的揚聲器數量。

    單聲道(Mono)和雙聲道(Stereo)比較常見,顧名思義,前者的聲道數為1,後者為2

    4. 音頻幀(frame)

    是用於測量显示幀數的量度。所謂的測量單位為每秒显示幀數(Frames per Second,簡稱:FPS)或“赫茲”(Hz)。

    音頻跟視頻很不一樣,視頻每一幀就是一張圖像,而從上面的正玄波可以看出,音頻數據是流式的,本身沒有明確的一幀幀的概念,在實際的應用中,為了音頻算法處理/傳輸的方便,一般約定俗成取2.5ms~60ms為單位的數據量為一幀音頻。

    這個時間被稱之為“採樣時間”,其長度沒有特別的標準,它是根據編×××和具體應用的需求來決定的,我們可以計算一下一幀音頻幀的大小:

    假設某通道的音頻信號是採樣率為8kHz,位寬為16bit,20ms一幀,雙通道,則一幀音頻數據的大小為:

    int size = 8000 x 16bit x 0.02s x 2 = 5120 bit = 640 byte

    五、常見的音頻編碼方式有哪些?

    上面提到過,模擬的音頻信號轉換為数字信號需要經過採樣和量化,量化的過程被稱之為編碼,根據不同的量化策略,產生了許多不同的編碼方式,常見的編碼方式有:PCM 和 ADPCM,這些數據代表着無損的原始数字音頻信號,添加一些文件頭信息,就可以存儲為WAV文件了,它是一種由微軟和IBM聯合開發的用於音頻数字存儲的標準,可以很容易地被解析和播放。

    我們在音頻開發過程中,會經常涉及到WAV文件的讀寫,以驗證採集、傳輸、接收的音頻數據的正確性。

    六、常見的音頻壓縮格式有哪些?

    首先簡單介紹一下音頻數據壓縮的最基本的原理:因為有冗餘信息,所以可以壓縮。

    (1) 頻譜掩蔽效應: 人耳所能察覺的聲音信號的頻率範圍為20Hz~20KHz,在這個頻率範圍以外的音頻信號屬於冗餘信號。

    (2) 時域掩蔽效應: 當強音信號和弱音信號同時出現時,弱信號會聽不到,因此,弱音信號也屬於冗餘信號。

    下面簡單列出常見的音頻壓縮格式:

    MP3,AAC,OGG,WMA,Opus,FLAC,APE,m4a,AMR,等等

    七、Adndroid VoIP相關的開源應用有哪些 ?

    imsdroid,sipdroid,csipsimple,linphone,WebRTC 等等

    八、音頻算法處理的開源庫有哪些 ?

    speex、ffmpeg,webrtc audio module(NS、VAD、AECM、AGC),等等

    九、Android提供了哪些音頻開發相關的API?

    音頻採集: MediaRecoder,AudioRecord

    音頻播放: SoundPool,MediaPlayer,AudioTrack

    音頻編解碼: MediaCodec

    NDK API: OpenSL ES

    十、音頻開發的延時標準是什麼?

    ITU-TG.114規定,對於高質量語音可接受的時延是300ms。一般來說,如果時延在300~400ms,通話的交互性比較差,但還可以接受。時延大於400ms時,則交互通信非常困難。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※帶您來看台北網站建置台北網頁設計,各種案例分享