月度归档:2017年01月

js监听radiobox

纯js方式

<html>
 <head>
  <script type ="text/JavaScript">
  function judgeGender()
  {
   var obj =document.getElementsByName("gender");
   for(var i =0;i < obj.length;i++)
   {
    if(obj[i].checked)
    {
      alert('你选择了:'+ obj[i].value);
    }
   }
  }
  </script>
 </head>
 <body>
  <input type ="radio" name = "gender" value = "男" onchange ="judgeGender();">男 <br>
  <input type ="radio" name = "gender" value = "女" onchange ="judgeGender();">女 <br>
 </body>
</html>

jq方式

//later

第一个只出现一次的字符

题目描述

在一个字符串(1<=字符串长度<=10000,全部由大写字母组成)中找到第一个只出现一次的字符,并返回它的位置

思路

两次循环
第一次循环求出现的次数
第二次循环求答案

代码

public int FirstNotRepeatingChar(String str) {
            //辅组数组
            int[] cnt=new int['z'-'A'+1];
            for(int i=0;i<str.length();i++){
                cnt[str.charAt(i)-'A']++;
            }
            for(int i=0;i<str.length();i++){
                if(cnt[str.charAt(i)-'A']==1){
                    return i;
                }
            }
            return -1;
        }

数组中重复的数字

题目描述

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。

代码

直接排序进行比较(好像没啥意思)

public boolean duplicate(int numbers[],int length,int [] duplication) {
            if(length==0||length==1)return false;
            Arrays.sort(numbers);
            for(int i=1;i<length;i++){
                if(numbers[i]==numbers[i-1]){
                    duplication[0]=numbers[i];
                    return true;
                }
            }
            return false;
}

辅组数组

 public boolean duplicate(int numbers[],int length,int [] duplication) {
            if(length==0||length==1)return false;
            boolean[] flag=new boolean[length];
            for(int i=0;i<length;i++){
                if(flag[numbers[i]]==true){
                    duplication[0]=numbers[i];
                    return true;
                }else {
                    flag[numbers[i]]=true;
                }
            }
            return false;
        }

还有可以用哈希吧

求1+2+3+…+n

题目描述

求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

思路

递归
利用&&的短路特性实现if语句
temp 没有用,只是为了构成一个语句

代码

public int Sum_Solution(int n) {
          int result = 0;
          boolean temp=(n!=0)&&(1==(result=result+n+Sum_Solution(n-1)));
          return result;
}

扑克牌顺子

题目描述

LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…..LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何。为了方便起见,你可以认为大小王是0。

思路

1.升序排序
2.得到大小王个数
3.从不是大小王的第一个数开始
4.缺一个就大小王个数减一,不够补跳出
5.没有牌了也跳出
6.判断

代码

 public boolean isContinuous(int [] numbers) {
          if(numbers==null||numbers.length==0)return false;
          Arrays.sort(numbers);
          int kingNum=0;
          //先统计大小王的个数
          for(int i=0;i<numbers.length;i++){
              if(numbers[i]==0){
                  kingNum++;
              }else{
                  break;
              }
          }
          int k=numbers[kingNum];
          int i;
          for(i=kingNum;i<numbers.length;){
              if(k==numbers[i]){
                  k++;
                  i++;
              }else {
                k++;
                if(kingNum>0){
                    kingNum--;
                }else {
                    break;
                }

            }
          }
          return k-1==numbers[i-1];
        }

翻转单词顺序列

题目描述

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

思路

通过空格分单词,然后倒序连接

代码

//翻转句子
      public String ReverseSentence(String str) {
          if(str==null||str.equals(""))return "";
          if(str.trim().equals(""))return str;
          String[] words=str.split(" ");
          StringBuilder sb=new StringBuilder();
          sb.append(words[words.length-1]);
          for(int i=words.length-2;i>=0;i--){
              sb.append(" "+words[i]);
          }
          return sb.toString();
      }

数据库设计学习笔记

为什么要进行数据库设计

优良的设计

  • 减少数据冗余
  • 避免数据库维护异常
  • 节约存储空间
  • 高效的访问

糟糕的设计

  • 存在大量的数据冗余
  • 存在数据插入、更新、删除异常
  • 浪费大量存储空间
  • 访问数据低效

数据库设计步骤

  1. 需求分析
  2. 逻辑设计
  3. 物理设计
  4. 维护优化

需求分析

  • 数据是什么
  • 数据有哪些属性
  • 数据和属性各自的特点有哪些

逻辑设计

  • 使用ER图都数据库进行逻辑设计
  • 同选用的DBMS无关

名词解释

  • 关系: 一个关系对应通常所说的一张表
  • 元组: 表中的一行
  • 属性: 表中的一列
  • 候选码: 可以唯一确定一个元组的属性组
  • 主码:其中一个候选码
  • 域: 属性的取值范围
  • 分量: 元组中的一个属性值

ER图概要

  • 矩形: 实体
  • 椭圆: 属性
  • 菱形: 操作(关系)
  • 线段:联系

操作异常

  • 插入异常
  • 更新异常
  • 删除异常

范式

第一范式

要求数据库字段都是不可再分的(原子性)
换句话说就是要求数据库中的表都是二维表

第二范式

数据库中的表不存在非关键字字段对任一候选关键字段的部分函数依赖
部分依赖是组合关键字中,某一关键字决定某字段的情况

第三范式

不存在传递依赖

BC范式

如果是复合关键字,关键字字段之间不能存在函数依赖

物理设计

选择合适的数据库管理系统

表及字段的命名规则

  • 可读性原则
  • 表意性原则
  • 长名原则

字段类型选择原则

当一个列可以选择多种数据类型进行存储的时候,应该优先考虑数字类型,其次是日期或者二进制类型,最后是字符串类型。对于相同级别的数据类型,应该优先选择占用空间小的类型。

字段大小如下(来自慕课网课程截图)

char与varchar的选择
  • 列中长度差不多同样长的优先考虑char 否则考虑varchar
  • 列中最大数据长度小于50Byte,优先考虑char
  • char字段不宜大于50Byte
decimal与float的选择
  • 精确数据只能选用decimal
  • 非精确数据优先float

主键选择

  • 区分业务主键和数据库主键
  • 考虑主键是否要自动增长
  • 主键类型占用空间尽可能小

避免使用外键约束

  • 降低数据导入的效率
  • 增加维护成本
  • 虽然不建议使用外键约束,但是相关联的列上一定要建立索引

避免使用触发器

  • 降低数据导入的效率
  • 可能会出现意想不到的数九异常
  • 使业务逻辑变得复杂

严禁使用预留字段

  • 无法准确的知道预留字段的类型
  • 无法准确的知道预留字段的所存储的内容
  • 后期维护一个预留字段的的代价和增加一个字段的代价相同

反范式化

简单来说就是增加冗余以空间换时间
比如增加冗余字段,可以减少表的连接,提高了效率,但是违反了第三范式(有了传递)

维护和优化

维护数据字典

  1. 使用第三方工具进行维护
  2. 使用数据库自带的备注进行维护
  3. 到处数据字典

维护索引

选择合适的列建立索引
  • 出现在where ,group by,order by 从句中的列
  • 可选择性高的列应放到索引的前面
  • 索引中不要包含太长的数据类型
注意点
  • 索引要适量,过多的索引会使读写的效率都降低
  • 定期维护索引碎片
  • 在SQL语句中不要使用强制索引关键字

维护表结构

注意点
  • 使用在线变更别结构的工具(MySQL5.6以后本身支持)
  • 同时对数据字典进行维护
  • 控制表的宽度和大小(表的拆分)
表的垂直拆分

把一个宽表拆分为若干窄表,经常查出的列应该放同一张子表中,以此提高查询效率

表的水平拆分

当一个表中的数据量过多的时候,通过对主键进行哈希,尽量平均分到多个子表当中,以此提高查询效率
也就是说表的垂直拆分是为了解决表太宽的问题,而水平拆分是解决表太长的问题

调整数组顺序使奇数位于偶数前面

题目描述

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

思路

直接分两次for循环遍历一次 时间复杂度O(n)

代码

public void reOrderArray(int [] array) {
          int[] temp=Arrays.copyOf(array, array.length);
          int j=0;
          for(int i=0;i<array.length;i++){
              if(temp[i]%2==1){ //奇数
                  array[j++]=temp[i];
              }
          }
          for(int i=0;i<array.length;i++){
              if(temp[i]%2==0){ //奇数
                  array[j++]=temp[i];
              }
          }
      }

数值的整数次方

题目描述

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

思路

分治法,算过的就不要再算一遍了

代码

第一段代码为连乘 第二段代码为分治

public double Power(double base, int exponent) {
            int res=1;
            for(int i=0;i<Math.abs(exponent);i++){
                res*=base;
            }
            return exponent>=0?res:1.0/res;
      }
      public double Power2(double base, int exponent) {

           if(exponent==0)return 1.0;
           if(exponent==1)return base;
           if(exponent==-1)return 1.0/base;
           if(base==0)return 0;

           int abse=Math.abs(exponent);
           double res=Power2(base, abse/2);
           res*=res;
           if(abse%2==1)res*=base;

           return exponent>0?res:1.0/res;
      }

矩形覆盖

题目描述

我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

思路

递推思想
设f(n)为第n个小矩形时的解,若f(0),f(1),..f(n-1)都已经求解出来,如何求f(n)呢,看图

第一个图,长为n,无颜色部分为n-1

第二个图,长为n,无颜色部分为n-2

要求f(n) 其实只是在f(n-1)和f(n-2)的基础上求而已
在f(n-1)和f(n-2)已经有解的情况下,再多家一块矩形,加的情况也就只有两种,一种是直接竖着补在最后面,另一种是横着补,但是这要动了前一块的小矩形,所以f(n)=f(n-1)+f(n-2)

代码

public class Solution {
    public int RectCover(int n) {
        if(n==0)return 0;
        if(n==1)return 1;
        int[] f=new int[n+1];
        f[0]=f[1]=1;
        for(int i=2;i<=n;i++){
            f[i]=f[i-1]+f[i-2];
        }
        return f[n];
     }

}

优化

可以把数组去掉