Quantcast
Channel: CSDN博客推荐文章
Viewing all 35570 articles
Browse latest View live

poj3281--Dining(最大流(EK算法))

$
0
0

题目来源:http://poj.org/problem?id=3281

题意

给出n头牛,d杯饮料(都比我过得好。。。T^T),以及f份食物,每头牛有各自喜欢的食物和饮料,那么每头牛吃饱喝好才算可以,所以问给出的东西能令多少牛吃饱。。。(吃完就没啦。。。)

思路

或许这道题可以弄成三分图匹配(胡诌的。。)。。
但是这是一道最大流模板题,本菜采用的最糟糕的EK算法,主要的一点就是如何去构图,,,
对于样例,构建如下图:
这里写图片描述
为啥cow要到cow,为了防止cow被重复使用,用边去判断是否使用过。。

代码

#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100+10;
int n,f,d,s,t;
int F[maxn][maxn],D[maxn][maxn];
int c[maxn*5][maxn*5],vis[maxn*5],pre[maxn*5];
void init()
{
    scanf("%d%d%d",&n,&f,&d);
    memset(F,0,sizeof(F));
    memset(D,0,sizeof(D));
    for(int i=1; i<=n; i++)
    {
        int ff,dd;
        scanf("%d%d",&ff,&dd);
        while(ff--)
        {
            int x;
            scanf("%d",&x);
            F[i][x]=1;
        }
        while(dd--)
        {
            int y;
            scanf("%d",&y);
            D[i][y]=1;
        }
    }
}
bool bfs()
{
    memset(vis,0,sizeof(vis));
    queue<int> Q;
    while(!Q.empty()) Q.pop();
    Q.push(s);
    vis[s]=1;
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        for(int v=s;v<=t;v++)
        {
            if(!vis[v]&&c[u][v]>0)
            {
                pre[v]=u;
                if(v==t)
                    return 1;
                Q.push(v);
                vis[v]=1;
            }
        }
    }
    return 0;
}

void print_EK()
{
    s=0,t=f+d+2*n+1;
    int maxflow=0;
    while(bfs())
    {
        int tt=t;
        while(tt!=s)
        {
            c[pre[tt]][tt]--;
            c[tt][pre[tt]]++;
            tt=pre[tt];
        }
        maxflow++;
    }
    printf("%d\n",maxflow);

}
void build_graph()//一共f+2*n+d+2个点,0~f+2*n+d+1
{
    memset(c,0,sizeof(c));
    for(int i=1; i<=f; i++) //s->food
        c[0][i]=1;
    for(int i=f+2*n+1; i<=f+2*n+d; i++) //drink->t
        c[i][f+2*n+d+1]=1;
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=f; j++) //food-->cow
            if(F[i][j])
                c[j][f+i]=1;
            c[f+i][f+n+i]=1;//cow-->cow
        for(int j=1; j<=d; j++) //cow-->drink
            if(D[i][j])
                c[f+n+i][f+2*n+j]=1;
    }
}
int main()
{
    init();
    build_graph();//建图。。
    print_EK();
    return 0;
}
//网络流第一道题,,,患得患失。。好菜,,,
作者:duan_1998 发表于2017/11/27 12:58:03 原文链接
阅读:60 评论:0 查看评论

CTF脚本--常见源码泄露扫描

$
0
0

web题经常会遇到源码泄露,在发现源码后进行源码审计最终获取flag,每次根据经验去一个一个的尝试,无疑是非常复杂的,这里使用python3.5打造了一个源码扫描python脚本

使用说明: python file_scan.py url –add x1.php …. xn.php

扫描范围:
这里写图片描述
核心代码:
这里写图片描述
这里写图片描述

源码放到了我的github上,欢迎师傅们提供修改意见~

作者:wy_97 发表于2017/11/27 15:15:29 原文链接
阅读:71 评论:0 查看评论

hdu1532--Drainage Ditches(最大流(EK算法))

$
0
0

题目来源:http://acmshowproblem.php?pid=1532

题意

给出m条边,n个点,问最大流量。。。

思路

EK算法模板。。。哇,找了半天的bug,,,原来是return 0写在了while循环里面。。。哇。。。好气哦。。。是真的气、。。。
但是也让我趁机明白了原来残量网络数组的最后结果并不一定是每条边最后的流量,,,只有再加一个实流网络才可以,,,

代码

#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200+19;
const int INF=0x3f3f3f3f;
int n,m;
int pre[maxn],f_l[maxn][maxn];
bool vis[maxn];
void init()
{
    memset(f_l,0,sizeof(f_l));
    while(m--)
    {
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        f_l[x][y]+=w;
    }
}
bool bfs()
{
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    queue<int> Q;
    Q.push(1);
    vis[1]=1;
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        for(int v=1; v<=n; v++)
        {
            if(!vis[v]&&f_l[u][v])
            {
                pre[v]=u;
                vis[v]=1;
                if(v==n) return 1;
                Q.push(v);
            }
        }
    }
    return 0;
}

void print_EK()
{
    int maxflow=0;
    while(bfs())
    {
        int tt=n,minn=INF;
        while(tt!=1)
        {
            minn=min(f_l[pre[tt]][tt],minn);
            tt=pre[tt];
        }
        maxflow+=minn;
        tt=n;
        while(tt!=1)
        {
            f_l[pre[tt]][tt]-=minn;
            f_l[tt][pre[tt]]+=minn;
            tt=pre[tt];
        }
    }
    printf("%d\n",maxflow);
}
int main()
{
    while(~scanf("%d%d",&m,&n))
    {
        init();
        print_EK();
    }
    return 0;
}
作者:duan_1998 发表于2017/11/27 15:34:05 原文链接
阅读:72 评论:0 查看评论

hdu3549--Flow Problem(最大流(EK算法))

$
0
0

题目来源:http://showproblem.php?pid=3549

题意

给出一个网络,求最大流、。。。

思路

好像并没有什么思路,模板硬上,,,
刷了三道水题了,,终于可以去学学ISAP了。。。(好菜。。。欲哭无泪状。。。)

代码

#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=19+10;
const int INF=0x3f3f3f3f;
int n,m;
int pre[maxn],f_l[maxn][maxn];
bool vis[maxn];
void init()
{
    scanf("%d%d",&n,&m);
    memset(f_l,0,sizeof(f_l));
    while(m--)
    {
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        f_l[x][y]+=w;
    }
}
bool bfs()
{
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    queue<int> Q;
    Q.push(1);
    vis[1]=1;
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        for(int v=1; v<=n; v++)
        {
            if(!vis[v]&&f_l[u][v])
            {
                pre[v]=u;
                vis[v]=1;
                if(v==n) return 1;
                Q.push(v);
            }
        }
    }
    return 0;
}

void print_EK()
{
    int maxflow=0;
    while(bfs())
    {
        int tt=n,minn=INF;
        while(tt!=1)
        {
            minn=min(f_l[pre[tt]][tt],minn);
            tt=pre[tt];
        }
        maxflow+=minn;
        tt=n;
        while(tt!=1)
        {
            f_l[pre[tt]][tt]-=minn;
            f_l[tt][pre[tt]]+=minn;
            tt=pre[tt];
        }
    }
    printf("%d\n",maxflow);
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int i=1;i<=T;i++)
    {
        init();
        printf("Case %d: ",i);
        print_EK();
    }
    return 0;
}
作者:duan_1998 发表于2017/11/27 15:42:36 原文链接
阅读:71 评论:0 查看评论

Go实战--golang中使用echo框架、MongoDB、JWT搭建REST API(labstack/echo、gopkg.in/mgo.v2、dgrijalva/jwt-go)

$
0
0

生命不止,继续go go go !!!

之前介绍过golang中restful api的博客,是使用redis作为持久化,httprouter作为框架:
Go实战–通过httprouter和redis框架搭建restful api服务(github.com/julienschmidt/httprouter)

今天,继续echo框架,这次加入mongodb作为持久化存储,使用jwt进行验证,来搭建一套rest api,类似Twitter。

其中,很多知识点之前都有介绍过:
关于golang中使用mongodb科技参考:
Go实战–golang使用ssl连接MongoDB(mgo)

Go实战–golang中使用MongoDB(mgo)

关于golang中的使用jwt(JSON Web Token):
Go实战–golang中使用JWT(JSON Web Token)

代码结构:

./model
   post.go
   user.go
./handler
   handler.go
   post.go
   user.go
main.go

model

这里没有什么好说的,就是建立model,需要注意的就是golang中struct中的标签。
一个用户user,一个邮箱post。

user.go

package model

import (
    "gopkg.in/mgo.v2/bson"
)

type (
    User struct {
        ID        bson.ObjectId `json:"id" bson:"_id,omitempty"`
        Email     string        `json:"email" bson:"email"`
        Password  string        `json:"password,omitempty" bson:"password"`
        Token     string        `json:"token,omitempty" bson:"-"`
        Followers []string      `json:"followers,omitempty" bson:"followers,omitempty"`
    }
)

post.go

package model

import (
    "gopkg.in/mgo.v2/bson"
)

type (
    Post struct {
        ID      bson.ObjectId `json:"id" bson:"_id,omitempty"`
        To      string        `json:"to" bson:"to"`
        From    string        `json:"from" bson:"from"`
        Message string        `json:"message" bson:"message"`
    }
)

handler

handler.go
handler中提出出来的公共部分。

package handler

import (
    "gopkg.in/mgo.v2"
)

type (
    Handler struct {
        DB *mgo.Session
    }
)

const (
    // Key (Should come from somewhere else).
    Key = "secret"
)

post.go
post中加入两个功能,一个创建post,一个拉取post。
关于”net/http”可以参考:
Go语言学习之net/http包(The way to go)
关于”strconv”可以参考:
Go语言学习之strconv包(The way to go)

package handler

import (
    "go_echo_examples/twitter/model"
    "net/http"
    "strconv"

    "github.com/labstack/echo"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

func (h *Handler) CreatePost(c echo.Context) (err error) {
    u := &model.User{
        ID: bson.ObjectIdHex(userIDFromToken(c)),
    }
    p := &model.Post{
        ID:   bson.NewObjectId(),
        From: u.ID.Hex(),
    }
    if err = c.Bind(p); err != nil {
        return
    }

    // Validation
    if p.To == "" || p.Message == "" {
        return &echo.HTTPError{Code: http.StatusBadRequest, Message: "invalid to or message fields"}
    }

    // Find user from database
    db := h.DB.Clone()
    defer db.Close()
    if err = db.DB("twitter").C("users").FindId(u.ID).One(u); err != nil {
        if err == mgo.ErrNotFound {
            return echo.ErrNotFound
        }
        return
    }

    // Save post in database
    if err = db.DB("twitter").C("posts").Insert(p); err != nil {
        return
    }
    return c.JSON(http.StatusCreated, p)
}

func (h *Handler) FetchPost(c echo.Context) (err error) {
    userID := userIDFromToken(c)
    page, _ := strconv.Atoi(c.QueryParam("page"))
    limit, _ := strconv.Atoi(c.QueryParam("limit"))

    // Defaults
    if page == 0 {
        page = 1
    }
    if limit == 0 {
        limit = 100
    }

    // Retrieve posts from database
    posts := []*model.Post{}
    db := h.DB.Clone()
    if err = db.DB("twitter").C("posts").
        Find(bson.M{"to": userID}).
        Skip((page - 1) * limit).
        Limit(limit).
        All(&posts); err != nil {
        return
    }
    defer db.Close()

    return c.JSON(http.StatusOK, posts)
}

user.go
这部分包括用户注册、登录、添加follow。
关于time包可以参考:
Go语言学习之time包(获取当前时间戳等)(the way to go)

package handler

import (
    "go_echo_examples/twitter/model"
    "net/http"
    "time"

    "github.com/dgrijalva/jwt-go"
    "github.com/labstack/echo"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

func (h *Handler) Signup(c echo.Context) (err error) {
    // Bind
    u := &model.User{ID: bson.NewObjectId()}
    if err = c.Bind(u); err != nil {
        return
    }

    // Validate
    if u.Email == "" || u.Password == "" {
        return &echo.HTTPError{Code: http.StatusBadRequest, Message: "invalid email or password"}
    }

    // Save user
    db := h.DB.Clone()
    defer db.Close()
    if err = db.DB("twitter").C("users").Insert(u); err != nil {
        return
    }

    return c.JSON(http.StatusCreated, u)
}

func (h *Handler) Login(c echo.Context) (err error) {
    // Bind
    u := new(model.User)
    if err = c.Bind(u); err != nil {
        return
    }

    // Find user
    db := h.DB.Clone()
    defer db.Close()
    if err = db.DB("twitter").C("users").
        Find(bson.M{"email": u.Email, "password": u.Password}).One(u); err != nil {
        if err == mgo.ErrNotFound {
            return &echo.HTTPError{Code: http.StatusUnauthorized, Message: "invalid email or password"}
        }
        return
    }

    //-----
    // JWT
    //-----

    // Create token
    token := jwt.New(jwt.SigningMethodHS256)

    // Set claims
    claims := token.Claims.(jwt.MapClaims)
    claims["id"] = u.ID
    claims["exp"] = time.Now().Add(time.Hour * 72).Unix()

    // Generate encoded token and send it as response
    u.Token, err = token.SignedString([]byte(Key))
    if err != nil {
        return err
    }

    u.Password = "" // Don't send password
    return c.JSON(http.StatusOK, u)
}

func (h *Handler) Follow(c echo.Context) (err error) {
    userID := userIDFromToken(c)
    id := c.Param("id")

    // Add a follower to user
    db := h.DB.Clone()
    defer db.Close()
    if err = db.DB("twitter").C("users").
        UpdateId(bson.ObjectIdHex(id), bson.M{"$addToSet": bson.M{"followers": userID}}); err != nil {
        if err == mgo.ErrNotFound {
            return echo.ErrNotFound
        }
    }

    return
}

func userIDFromToken(c echo.Context) string {
    user := c.Get("user").(*jwt.Token)
    claims := user.Claims.(jwt.MapClaims)
    return claims["id"].(string)
}

main

最后的main.go就相对很简单了。
main.go

package main

import (
    "go_echo_examples/twitter/handler"

    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
    "github.com/labstack/gommon/log"
    "gopkg.in/mgo.v2"
)

func main() {
    e := echo.New()
    e.Logger.SetLevel(log.ERROR)
    e.Use(middleware.Logger())
    e.Use(middleware.JWTWithConfig(middleware.JWTConfig{
        SigningKey: []byte(handler.Key),
        Skipper: func(c echo.Context) bool {
            // Skip authentication for and signup login requests
            if c.Path() == "/login" || c.Path() == "/signup" {
                return true
            }
            return false
        },
    }))

    // Database connection
    db, err := mgo.Dial("localhost")
    if err != nil {
        e.Logger.Fatal(err)
    }

    // Create indices
    if err = db.Copy().DB("twitter").C("users").EnsureIndex(mgo.Index{
        Key:    []string{"email"},
        Unique: true,
    }); err != nil {
        log.Fatal(err)
    }

    // Initialize handler
    h := &handler.Handler{DB: db}

    // Routes
    e.POST("/signup", h.Signup)
    e.POST("/login", h.Login)
    e.POST("/follow/:id", h.Follow)
    e.POST("/posts", h.CreatePost)
    e.GET("/feed", h.FetchPost)

    // Start server
    e.Logger.Fatal(e.Start(":1323"))
}

测试

启动mongodb服务

mongod.exe --dbpath d:\mongodb_data\db

成功的话,结果:

2017-11-27T00:17:22.201-0700 I CONTROL  [initandlisten] MongoDB starting : pid=17792 port=27017 dbpath=d:\mongodb_data\db 64-bit host=LAPTOP-MNU6522J
2017-11-27T00:17:22.202-0700 I CONTROL  [initandlisten] targetMinOS: Windows 7/Windows Server 2008 R2
2017-11-27T00:17:22.202-0700 I CONTROL  [initandlisten] db version v3.4.6
2017-11-27T00:17:22.203-0700 I CONTROL  [initandlisten] git version: c55eb86ef46ee7aede3b1e2a5d184a7df4bfb5b5
2017-11-27T00:17:22.203-0700 I CONTROL  [initandlisten] OpenSSL version: OpenSSL 1.0.1u-fips  22 Sep 2016
2017-11-27T00:17:22.204-0700 I CONTROL  [initandlisten] allocator: tcmalloc
2017-11-27T00:17:22.204-0700 I CONTROL  [initandlisten] modules: none
2017-11-27T00:17:22.204-0700 I CONTROL  [initandlisten] build environment:
2017-11-27T00:17:22.204-0700 I CONTROL  [initandlisten]     distmod: 2008plus-ssl
2017-11-27T00:17:22.205-0700 I CONTROL  [initandlisten]     distarch: x86_64
2017-11-27T00:17:22.205-0700 I CONTROL  [initandlisten]     target_arch: x86_64
2017-11-27T00:17:22.205-0700 I CONTROL  [initandlisten] options: { storage: { dbPath: "d:\mongodb_data\db" } }
2017-11-27T00:17:22.261-0700 I -        [initandlisten] Detected data files in d:\mongodb_data\db created by the 'wiredTiger' storage engine, so setting the active storage engine to 'wiredTiger'.
2017-11-27T00:17:22.271-0700 I STORAGE  [initandlisten] wiredtiger_open config: create,cache_size=3540M,session_max=20000,eviction=(threads_min=4,threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics_log=(wait=0),
2017-11-27T00:17:24.247-0700 I CONTROL  [initandlisten]
2017-11-27T00:17:24.248-0700 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2017-11-27T00:17:24.259-0700 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2017-11-27T00:17:24.260-0700 I CONTROL  [initandlisten]
2017-11-27T15:17:25.037+0800 I FTDC     [initandlisten] Initializing full-time diagnostic data capture with directory 'd:/mongodb_data/db/diagnostic.data'
2017-11-27T15:17:25.046+0800 I NETWORK  [thread1] waiting for connections on port 27017

运行main.go
mongodb控制台:

2017-11-27T15:23:39.223+0800 I NETWORK  [thread1] connection accepted from 127.0.0.1:51150 #2 (1 connection now open)
2017-11-27T15:23:39.501+0800 I INDEX    [conn2] build index on: twitter.users properties: { v: 2, unique: true, key: { email: 1 }, name: "email_1", ns: "twitter.users" }
2017-11-27T15:23:39.501+0800 I INDEX    [conn2]          building index using bulk method; build may temporarily use up to 500 megabytes of RAM
2017-11-27T15:23:39.529+0800 I INDEX    [conn2] build index done.  scanned 0 total records. 0 secs
2017-11-27T15:23:39.530+0800 I COMMAND  [conn2] command twitter.$cmd command: createIndexes { createIndexes: "users", indexes: [ { name: "email_1", ns: "twitter.users", key: { email: 1 }, unique: true } ] } numYields:0 reslen:113 locks:{ Global: { acquireCount: { r: 1, w: 1 } }, Database: { acquireCount: { W: 1 } }, Collection: { acquireCount: { w: 1 } } } protocol:op_query 303ms

用户注册
使用postman或是curl命令,这里使用curl命令了:

curl -X POST http://localhost:1323/signup -H "Content-Type:application/json" -d '{"email" :"wangshubo1989@126.co"m", "password":"test"}'

登录

curl -X POST http://localhost:1323/login -H "Content-Type:application/json" -d '{"email" :"wangshubo1989@126.com", "password":"test"}'

返回:

{"id":"5a1bbe92271c7c5ac875e40e","email":"wangshubo1989@126.com","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MTIwMjcwOTgsImlkIjoiNWExYmJlOTIyNzFjN2M1YWM4NzVlNDBlIn0.V__5q0fipKfPhcGop1rDiOX5lFc7qSVz9bVfJ5zycvo"}

Follow用户

curl -X POST http://localhost:1323/follow/5a1bbe92271c7c5ac875e40e -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MTIwMjcwOTgsImlkIjoiNWExYmJlOTIyNzFjN2M1YWM4NzVlNDBlIn0.V__5q0fipKfPhcGop1rDiOX5lFc7qSVz9bVfJ5zycvo"

发送消息(邮件)

curl -X POST http://localhost:1323/posts -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MTIwMjcwOTgsImlkIjoiNWExYmJlOTIyNzFjN2M1YWM4NzVlNDBlIn0.V__5q0fipKfPhcGop1rDiOX5lFc7qSVz9bVfJ5zycvo" -H "Content-Type: application/json" -d '{"to":"58465b4ea6fe886d3215c6df","message":"hello"}'

这里写图片描述

作者:wangshubo1989 发表于2017/11/27 15:45:02 原文链接
阅读:1089 评论:0 查看评论

RBAC从零开始--登录及登录拦截器

$
0
0

  并没有正真的做一个登录界面,只是做一个模拟登录的过程,但是对非登录状态访问内容时,对请求进行拦截。


  • 在controller包下新建一个类UserController.java
  • 在service包下新建一个UserService接口
  • 在service->impl包下新建一个UserServiceImpl,实现UserService里面的接口

UserController.java

@Controller
@RequestMapping("/user")
public class UserController {

    private static final Logger LOG = LoggerFactory.getLogger(UserController.class);

    @Resource
    private UserService userService;

    @SystemLog(description = "伪登录")
    @RequestMapping(value = "/vlogin" , method = RequestMethod.GET)
    public String vlogin(HttpSession httpSession
            , HttpServletRequest request , HttpServletResponse response, @RequestParam Integer uid) {

        User user = userService.vlogin(uid);

        if (user != null) {
            httpSession.setAttribute("user" , user);
            request.setAttribute("page" , PageEnum.INDEX.getCode());
        } else {
            request.setAttribute("page" , PageEnum.LOGIN_HINT.getCode());
        }

        return "./../../index";
    }
}

UserService.java

public interface UserService {
    User vlogin(int uid);
}

UserServiceImpl.java

@Service("userService")
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userDao;

    public User vlogin(int uid) {

       User user = userDao.selectByPrimaryKey(uid);

       return user;

    }
}

注:
@Repository("userRoleDao")
public interface UserRoleMapper {......}

PageEnum.java

public enum PageEnum {

    LOGIN_HINT("登录提示" , -1) ,
    INDEX("首页" , 0) ,
    TEST_ONE("测试页面一" , 1) ,
    TEST_TWO("测试页面二" , 2) ,
    TEST_THREE("测试页面三" , 3) ,
    TEST_FOUR("测试页面四" , 4) ,
    USER_LIST("用户列表" , 10) ,
    ROLE_LIST("角色列表" , 20) ,
    ACCESS_LIST("权限列表" , 30) ,
    NONE_ACCESS("无访问权限" , -9999);

    private String name;
    private int code;

    private PageEnum(String name , int code) {
        this.name = name;
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public int getCode() {
        return code;
    }
}

登录拦截器LoginInterceptor.java

public class LoginInterceptor extends HandlerInterceptorAdapter {

    private final Logger LOG = LoggerFactory.getLogger(LoginInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws ServletException, IOException {

        String url = request.getRequestURI();

        LOG.info("......进入拦截器的URL:[{}]......" , url);

        if (url.equals("/") || url.contains("/resources/") || url.equals("/user/vlogin")) {

            return true;

        }

        User user =  (User)request.getSession().getAttribute("user");

        if(user == null){
            LOG.info("......请先登录!......");
            request.getSession().setAttribute("msg" , "请登录,本实例没有登录页面,请使用伪登录");
            response.sendRedirect("/index.jsp");
            return false;
        }

        return true;

    }
}

spring-mvn.xml配置文件

<!--配置拦截器, 多个拦截器,顺序执行 -->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**" />
        <bean class="com.xll.interceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

login-hint.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <body>
        <span style="color: red;font-weight: bold;">未登录,本实例没有登录页面,请伪登录</span>
    </body>
</html>

rbac.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>

<body>

    <dl class="lemmaWgt-lemmaTitle lemmaWgt-lemmaTitle-">
        <dd class="lemmaWgt-lemmaTitle-title">
            <h1>RBAC</h1>
        </dd>
    </dl>

    <div class="lemma-summary" label-module="lemmaSummary">
        <div class="para" label-module="para">基于角色的权限访问控制(Role-Based Access Control)作为传统访问控制(自主访问,强制访问)的有前景的代替受到广泛的关注。在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据需要而从某角色中回收。角色与角色的关系可以建立起来以囊括更广泛的客观情况。</div>
    </div>

</body>
</html>

index.jsp界面,在文件的开头加上<%@ taglib uri=”http://java.sun.com/jsp/jstl/core” prefix=”c”%>

<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                    <ul class="nav navbar-nav">
                        <li><a href="/index.jsp">首页</a></li>
                    </ul>
                    <p class="navbar-text navbar-right">Hi

                        <c:if test="${sessionScope.user.isAdmin}">
                            <a href="javascript:void(0)" class="navbar-link">超级管理员(${sessionScope.user.name})</a>
                        </c:if>

                        <c:if test="${sessionScope.user.name != null && !sessionScope.user.isAdmin}">
                            <a href="javascript:void(0)" class="navbar-link">${sessionScope.user.name}</a>
                        </c:if>

                        <c:if test="${sessionScope.user.name == null}">
                            <a href="javascript:void(0)" class="navbar-link">请登录</a>
                        </c:if>

                    </p>
                </div>
<div class="col-sm-10 col-sm-offset-2 col-md-10 col-md-offset-2 col-lg-10 col-lg-offset-2">

                <c:if test="${sessionScope.user == null || requestScope.page == -1}">
                    <%@ include file="/WEB-INF/jsp/login-hint.jsp"%>
                </c:if>

                <c:if test="${requestScope.page == 0}">
                    <%@ include file="/WEB-INF/jsp/rbac.jsp"%>
                </c:if>

                <c:if test="${sessionScope.user != null && requestScope.page == null}">
                    <%@ include file="/WEB-INF/jsp/rbac.jsp"%>
                </c:if>

                <hr/>
                <footer>
                    <p class="pull-left">@编程少年夏小龙</p>

                    <p class="pull-right">Power by home www.jld.com</p>

                </footer>
            </div>

访问:http://localhost:8080/user/vlogin?uid=xxx即可


注:先向user表里面插入一条数据

下篇将编写用户管理中的用户查询

作者:xia744510124 发表于2017/11/27 16:06:03 原文链接
阅读:103 评论:0 查看评论

用FaceNet的模型计算人脸之间距离(TensorFlow)

$
0
0

2015年Google的研究人员发表了一篇论文:FaceNet: A Unified Embedding for Face Recognition and Clustering,是关于人脸识别的,他们训练一个网络来得到人脸的128维特征向量,从而通过计算特征向量之间的欧氏距离来得到人脸相似程度。在LFW上面取得了当时最好的成绩,识别率为99.63%。

传统的基于CNN的人脸识别方法为:利用CNN的siamese网络来提取人脸特征,然后利用SVM等方法进行分类。而这篇文章中他们提出了一个方法系统叫作FaceNet,它直接学习图像到欧式空间上点的映射,其中呢,两张图像所对应的特征的欧式空间上的点的距离直接对应着两个图像是否相似。

人脸之间距离

如上图所示,直接得出不同人脸图片之间的距离,通过距离就可以判断是否是同一个人,阈值大概在1.1左右。

而现在我要做的,就是用训练好的模型文件,实现任意两张人脸图片,计算其FaceNet距离。然后就可以将这个距离用来做其他的事情了。

环境

  • macOS 10.12.6
  • Python 3.6.3
  • TensorFlow 1.3.0

实现

模型文件

首先我们需要训练好的模型文件,这个可以在FaceNet官方的github中获取:

github的README中有

注意他们是存放在Google云盘中的,需要翻墙获取(没个翻墙能力连科研都做不好了。。)

代码

这里我们需要FaceNet官方的github中获取到的facenet.py文件以供调用,需要注意的是其github中的文件一直在更新,我参考的很多代码中用到的facenet.py文件里方法居然有的存在有的不存在,所以可能随着时间流逝有些现在能成功以后需要修改代码才能成功了。

代码如下:

# -*- coding: utf-8 -*-

import tensorflow as tf
import numpy as np
import scipy.misc
import cv2
import facenet

image_size = 200 #don't need equal to real image size, but this value should not small than this
modeldir = './model_check_point/20170512-110547.pb' #change to your model dir
image_name1 = 'x.jpg' #change to your image name
image_name2 = 'y.jpg' #change to your image name

print('建立facenet embedding模型')
tf.Graph().as_default()
sess = tf.Session()

facenet.load_model(modeldir)
images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0")
embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0")
phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0")
embedding_size = embeddings.get_shape()[1]

print('facenet embedding模型建立完毕')

scaled_reshape = []

image1 = scipy.misc.imread(image_name1, mode='RGB')
image1 = cv2.resize(image1, (image_size, image_size), interpolation=cv2.INTER_CUBIC)
image1 = facenet.prewhiten(image1)
scaled_reshape.append(image1.reshape(-1,image_size,image_size,3))
emb_array1 = np.zeros((1, embedding_size))
emb_array1[0, :] = sess.run(embeddings, feed_dict={images_placeholder: scaled_reshape[0], phase_train_placeholder: False })[0]

image2 = scipy.misc.imread(image_name2, mode='RGB')
image2 = cv2.resize(image2, (image_size, image_size), interpolation=cv2.INTER_CUBIC)
image2 = facenet.prewhiten(image2)
scaled_reshape.append(image2.reshape(-1,image_size,image_size,3))
emb_array2 = np.zeros((1, embedding_size))
emb_array2[0, :] = sess.run(embeddings, feed_dict={images_placeholder: scaled_reshape[1], phase_train_placeholder: False })[0]

dist = np.sqrt(np.sum(np.square(emb_array1[0]-emb_array2[0])))
print("128维特征向量的欧氏距离:%f "%dist)

代码的逻辑就是
1. 先导入模型参数
2. 然后导入两张图片,分别获取其经过模型后得到的128维特征向量
3. 最后计算两个向量的欧氏距离

代码中有几个参数:
* image_size:图片长宽尺寸,这里要求输入的图片是长宽相等的,但是不要求两张人脸图大小一致,这里设置的尺寸是代码中会将人脸图读取后重新拉伸压缩成这个大小,这个尺寸最好比200大,太小了会运行失败
* modeldir:预训练好的模型路径
* image_name1:第一张人脸图的图片名
* image_name2:第二张人脸图的图片名

实验

给两个不同人的人脸图片,得到的结果如下:

终端运行输出

如果比较两个相同的人脸图片,得到的距离会是零点几;如果是两张一样的图,得到的距离会是0,符合要求。

这里有我的工程代码:https://github.com/Cloudox/facenet_distance


查看作者首页

作者:Cloudox_ 发表于2017/11/27 16:09:03 原文链接
阅读:56 评论:0 查看评论

git: 简洁高效 的 双分支式 git flow (master + dev)

$
0
0

git flow 总结对比

Git 作为一个源码管理系统,不可避免涉及到多人协作。

使用 git branch (git 分支)进行版本控制,可以让大家有效地合作,使得项目井井有条地发展下去。

这里写图片描述

网络上关于 使用 git branch (git 分支)进行版本控制 的教程汗牛充栋。

它们提出了形形色色,功能各异的 分支方案

分支名 时效性 分支功能
master 长期分支 管理对外发布版本,每个 commit 对一个 tag,也就是一个发布版本
develop 长期分支 作为日常开发汇总,即开发版的代码
feature 短期分支 一个新功能的开发
hotfix 短期分支 正式发布以后,出现 bug,需要创建一个分支,进行 bug 修补。
release 短期分支 发布正式版本之前(即合并到 master 分支之前),需要有的预发布的版本进行测试。release 分支在经历测试之后,测试确认验收,将会被合并的 develop 和 master


然而,普通的 单人开发小型项目,是不需要这么大费周章的分支结构的。
过多的分支设计,容易导致:

  • 开发效率低下
  • 分支结构混乱

master + dev 双分支式 git flow

简而言之,对于 单人开发小型项目,我们往往只需要两个分支就够了。即:

分支名 分支名简写 分支功能
master master 主分支
develop dev 开发分支


这也是我日常进行单人独立开发所采用的分支结构。

具体 git flow 如下图所示:

这里写图片描述



作者:JNingWei 发表于2017/11/27 16:26:43 原文链接
阅读:55 评论:0 查看评论

ZCMU 1540 第k大数 (二分)

$
0
0



时间限制: 10 Sec  内存限制: 128 MB
提交: 74  解决: 22
[提交][状态][讨论版]

题目描述

有两个序列a,b,它们的长度分别为n和m,那么将两个序列中的元素对应相乘后得到的n*m个元素从大到小排列后的第k个元素是什么?

输入

输入的第一行为一个正整数T (T<=10),代表一共有T组测试数据。

每组测试数据的第一行有三个正整数n,m和k(1<=n, m<=100000,1<=k<=n*m),分别代表a序列的长度,b序列的长度,以及所求元素的下标。第二行为n个正整数代表序列a。第三行为m个正整数代表序列b。序列中所有元素的大小满足[1,100000]。

输出

对于每组测试数据,输出一行包含一个整数代表第k大的元素是多少。

样例输入

3
3 2 3
1 2 3
1 2
2 2 1
1 1
1 1
2 2 4
1 1
1 1

样例输出

3
1
1


【题意】

n*m 从大到小排序, 为第k个数是多少

【思路】

虽然时间给出10s  但 暴力扔会超时,  

数据太多,  通过用 二分 将时间复杂度降下来,  

二分 最大 a[n]*b[m]    到最小 a[1]*b[1] 直接的 答案;

再通过统计 比mid 大得个数 与 k  比较 进行  缩或扩


【代码实现】


//#include <bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <math.h>
#include <cstring>
#include <string>
#include <queue>
#include <deque>
#include <stack>
#include <stdlib.h>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <vector>
#define mem(a,b) memset(a,b,sizeof(a))
#define findx(x) lower_bound(b+1,b+1+bn,x)-b
#define FIN      freopen("input.txt","r",stdin)
#define FOUT     freopen("output.txt","w",stdout)
#define S1(n)    scanf("%d",&n)
#define SL1(n)   scanf("%I64d",&n)
#define S2(n,m)  scanf("%d%d",&n,&m)
#define SL2(n,m)  scanf("%I64d%I64d",&n,&m)
#define Pr(n)     printf("%d\n",n)
#define lson rt << 1, l, mid
#define rson rt << 1|1, mid + 1, r
#define  FI(n) IO::read(n)
#define  Be IO::begin()

using namespace std;
typedef long long ll;
const double PI=acos(-1);
const int INF=0x3f3f3f3f;
const double esp=1e-6;
const int maxn=1e5+5;
const int MAXN=50005;
const int MOD=1e9+7;
const int mod=1e9+7;
int dir[5][2]={0,1,0,-1,1,0,-1,0};

namespace IO {
	const int MT = 5e7;
	char buf[MT]; int c,sz;
	void begin(){
		c = 0;
		sz = fread(buf, 1, MT, stdin);//Ò»´ÎÐÔÊäÈë
	}
	template<class T>
	inline bool read(T &t){
		while( c < sz && buf[c] != '-' && ( buf[c]<'0' || buf[c] >'9')) c++;
		if( c>=sz) return false;
		bool flag = 0; if( buf[c]== '-') flag = 1,c++;
		for( t=0; c<=sz && '0' <=buf[c] && buf[c] <= '9'; c++ ) t= t*10 + buf[c]-'0';
		if(flag) t=-t;
		return true;
	}
}
ll inv[maxn*2];
inline void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){if(!b){ x=1; y=0; d=a; }else{ ex_gcd(b,a%b,d,y,x); y-=x*(a/b);};}
inline ll gcd(ll a,ll b){ return b?gcd(b,a%b):a;}
inline ll exgcd(ll a,ll b,ll &x,ll &y){if(!b){x=1;y=0;return a;}ll ans=exgcd(b,a%b,x,y);ll temp=x;x=y;y=temp-a/b*y;return ans;}
inline ll lcm(ll a,ll b){ return b/gcd(a,b)*a;}
inline ll qpow(ll x,ll n){ll res=1;for(;n;n>>=1){if(n&1)res=(res*x)%MOD;x=(x*x)%MOD;}return res;}
inline ll inv_exgcd(ll a,ll n){ll d,x,y;ex_gcd(a,n,d,x,y);return d==1?(x+n)%n:-1;}
inline ll inv1(ll b){return b==1?1:(MOD-MOD/b)*inv1(MOD%b)%MOD;}
inline ll inv2(ll b){return qpow(b,MOD-2);}
ll n,k,m;
ll a[maxn],b[maxn];
int judge(ll mid)
{
    int j=1;
    int  sum=0;
    for(int i=n;i>=1;i--)
    {
        while(j<=m)
        {
            if(a[i]*b[j]>=mid)
            {
                sum+=m-j+1;
                break;
            }
            else
            {
                j++;
            }
        }
    }
    return sum;
}


int main()
{
    int T;
    cin>>T;

    while(T--)
    {
        scanf("%lld %lld %lld",&n,&m,&k);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        for(int i=1;i<=m;i++)
            scanf("%lld",&b[i]);
        sort(a+1,a+n+1);
        sort(b+1,b+m+1);
        ll kl=a[1]*b[1];// ×îС 
        ll kr=a[n]*b[m];//×î´ó 
       ll ans=0;
        while(kl<=kr)
        {
            ll mid= (kl+kr)>>1;
            int  sum=judge(mid);
            if(sum>=k)// ±Èk´ó  ´ð°¸ÔÚÓÒ ÒªËõ 
            {
                ans=mid;
               // cout<<ans<<endl;
                kl=mid+1;
            }
            else// À© 
            {

                kr=mid-1;
            }

        }

        printf("%lld\n",ans);
    }
    return 0;
}
/*
5
5 2 8
1 2 3 4 5
1 2
*/


123


作者:sizaif 发表于2017/11/27 16:33:43 原文链接
阅读:65 评论:0 查看评论

UIAutomator2.0详解(UIDevice篇----Wait)

$
0
0

感觉拖了好久,今天将Wait接口的总结补上,顺便把SearchCondition也捎带结了。
直接上图。

这里写图片描述

Wait方法含义:查看查询条件是否符合,若符合,则返回结果。若不符合,则继续等待,直至超时。
返回结果可能为UIObject2对象或者UIObject2对象列表,或者布尔类型。

其中,传参SearchCondition是一个抽象类,若想获取其实体对象,需要调用Until工具类。
该类提供了4个接口方法,来返回SearchCondition实体对象。

public static SearchCondition<UiObject2> findObject(final BySelector selector) 
public static SearchCondition<List<UiObject2>> findObjects(final BySelector selector) 
public static SearchCondition<Boolean> hasObject(final BySelector selector) 
public static SearchCondition<Boolean> gone(final BySelector selector) 

这里着重说一下gone方法(前三个方法,从方法名称便可理解用途)。

该方法与findObject功能相反。若不存在符合查询条件的UI对象,则返回true,否则返回false。

还是通过示例来说明如何使用。核心代码如下。

public class WaitTest extends UIDeviceTest {

    private String text_button1 ="OPEN ACTIVITY 2";

    private String text_button2 ="OPEN ACTIVITY";

    private String text_check="check";

    private String mPackageName="com.breakloop.test";

    private String mActivityName=".MainActivity";

    private long timeout=2000l;

    @Before
    public void start(){
        Utils.startAPP(mDevice,mPackageName,mActivityName);
        waitForAMoment();
    }

    private void waitForAMoment(){
        mDevice.waitForWindowUpdate(mPackageName,timeout);
    }

    @After
    public void end(){
        Utils.closeAPP(mDevice,mPackageName);
        waitForAMoment();
    }

    @Test
    public void Test1(){
        UiObject2 ui2=null;
        List<UiObject2> uiObject2List=null;
        boolean result=false;

        Log.i(TAG, "Test: start");
        ui2=mDevice.wait(Until.findObject(By.text(text_button1)),timeout);
        Log.i(TAG, "Test1: "+(ui2!=null?"":"Do Not ")+"find UI with txt "+text_button1);

        ui2=mDevice.wait(Until.findObject(By.text(text_button2)),timeout);
        Log.i(TAG, "Test2: "+(ui2!=null?"":"Do Not ")+"find UI with txt "+text_button2);

        result=mDevice.wait(Until.hasObject(By.text(text_button1)),timeout);
        Log.i(TAG, "Test3: "+(result?"":"Do Not ")+"find UI with txt "+text_button1);

        result=mDevice.wait(Until.hasObject(By.text(text_button2)),timeout);
        Log.i(TAG, "Test4: "+(result?"":"Do Not ")+"find UI with txt "+text_button2);

        result=mDevice.wait(Until.gone(By.text(text_button1)),timeout);
        Log.i(TAG, "Test5: "+(result?"Do Not ":"")+"find UI with txt "+text_button1);

        result=mDevice.wait(Until.gone(By.text(text_button2)),timeout);
        Log.i(TAG, "Test6: "+(result?"Do Not ":"")+"find UI with txt "+text_button2);

        uiObject2List=mDevice.wait(Until.findObjects(By.textStartsWith(text_check)),timeout);
        Log.i(TAG, "Test7: "+(uiObject2List!=null?"":"Do Not ")+"find UI with txt "+text_check);
        if(uiObject2List!=null){
            for (UiObject2 item :
                    uiObject2List) {
                item.click();
                waitForAMoment();
            }
        }

        uiObject2List=mDevice.wait(Until.findObjects(By.text(text_check)),timeout);
        Log.i(TAG, "Test8: "+(uiObject2List!=null?"":"Do Not ")+"find UI with txt "+text_check);
        if(uiObject2List!=null){
            for (UiObject2 item :
                    uiObject2List) {
                item.click();
                waitForAMoment();
            }
        }
        Log.i(TAG, "Test: end");
    }
}

执行效果如图

这里写图片描述

执行结果如下

15:48:58.700 I/com.breakloop.u2demo.uidevice.WaitTest: Test: start
15:48:58.748 I/com.breakloop.u2demo.uidevice.WaitTest: Test1: find UI with txt OPEN ACTIVITY 2
15:49:00.876 I/com.breakloop.u2demo.uidevice.WaitTest: Test2: Do Not find UI with txt OPEN ACTIVITY
15:49:00.939 I/com.breakloop.u2demo.uidevice.WaitTest: Test3: find UI with txt OPEN ACTIVITY 2
15:49:03.078 I/com.breakloop.u2demo.uidevice.WaitTest: Test4: Do Not find UI with txt OPEN ACTIVITY
15:49:05.209 I/com.breakloop.u2demo.uidevice.WaitTest: Test5: find UI with txt OPEN ACTIVITY 2
15:49:05.249 I/com.breakloop.u2demo.uidevice.WaitTest: Test6: Do Not find UI with txt OPEN ACTIVITY
15:49:05.290 I/com.breakloop.u2demo.uidevice.WaitTest: Test7: find UI with txt check
15:49:11.620 I/com.breakloop.u2demo.uidevice.WaitTest: Test8: Do Not find UI with txt check
15:49:11.620 I/com.breakloop.u2demo.uidevice.WaitTest: Test: end

由执行结果可见:

对于Until.findObject,Until.findObjects,Until.hasObject三个方法,若找到符合查询条件的UI,则Wait结束,否则继续Wait,直至超时。

对于Until.gone方法,则相反。若找到符合查询条件的UI,则继续Wait,直至超时,否则,Wait结束。

作者:daihuimaozideren 发表于2017/11/27 17:55:56 原文链接
阅读:38 评论:0 查看评论

C++状态模式

$
0
0

简述

状态模式(State Pattern)是行为设计模式之一。当对象根据其内部状态改变其行为时,将使用状态设计模式。

版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820

模式结构

UML 结构图:

State Pattern

  • 上下文(Context):定义一个与 Client 交互的接口。它维护对 ConcreteState 对象的引用,可以用该对象来定义当前状态。
  • 抽象状态(State):定义接口,来声明每个 ConcreteState 应该做什么。
  • 具体状态(ConcreteState):为 State 中定义的方法提供实现。

优缺点

优点:

  • 实现多态行为的好处是显而易见的,并且很容易添加状态来支持额外的行为。
  • 在状态模式中,对象的行为是其状态中函数的结果,并且在运行时根据状态改变行为,这就消除了对 if/elseswitch/case 条件逻辑的依赖。
  • 可以提高内聚性,因为状态特定的行为被聚合到具体的类中,这些类被放在代码中的一个位置。

缺点:

  • 使用状态模式,必然会增加系统中类和对象的个数。
  • 由于状态模式的结构与实现较为复杂,一旦使用不当,将会导致程序结构和代码的混乱。
  • 若要添加新的状态,则需要修改负责转换的源代码,否则无法转换到新增的状态,而且修改某个状态的行为也要修改源代码。

使用场景

  • 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
  • 一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态。

案例分析

交通信号灯 - 文明出行,从我做起。

红灯停,绿灯行,黄灯亮了等一等。

Traffic Lights

交叉路口红绿灯,指挥交通显神通;
绿灯亮了放心走,红灯亮了别抢行;
黄灯亮了要注意,人人遵守红绿灯。

可以看到,交通信号灯的状态流:红灯 -> 绿灯 -> 黄灯。。。实际上,就是各个状态之间的相互切换,这完全符合状态模式。

代码实现

创建上下文

上下文由 TrafficLights 表示,该类有一个 IState 变量,在构造中被初始化为 RedLight(红灯):

// context.h
#ifndef CONTEXT_H
#define CONTEXT_H

#include "concrete_state.h"

// 交通信号灯
class TrafficLights
{
public:
    TrafficLights() { m_pState = new RedLight(this); }
    void SetState(IState* state) { m_pState = state; }
    void Request() { m_pState->Handle(); }

private:
    IState* m_pState;
};

#endif // CONTEXT_H

注意: 在上下文提供的方法中,实际上使用的是 IState 的相应方法。

创建抽象状态

IState 有一个 Handle() 接口,用于改变状态:

// state.h
#ifndef STATE_H
#define STATE_H

// 信号灯的状态
class IState
{
public:
    virtual void Handle() = 0;
};

#endif // STATE_H

创建具体状态

具体的状态有三个 - 红灯、绿灯、黄灯:

// concrete_state.h
#ifndef CONCRETE_STATE_H
#define CONCRETE_STATE_H

#include "state.h"

class TrafficLights;

// 红灯
class RedLight : public IState
{
public:
    RedLight(TrafficLights* context);
    virtual void Handle() override;

private:
    TrafficLights* m_pContext;
};

// 绿灯
class GreenLight : public IState
{
public:
    GreenLight(TrafficLights* context);
    virtual void Handle() override;

private:
    TrafficLights* m_pContext;
};

// 黄灯
class YellowLight : public IState
{
public:
    YellowLight(TrafficLights* context);
    virtual void Handle() override;

private:
    TrafficLights* m_pContext;
};

#endif // CONCRETE_STATE_H

它们所提供的方法有对上下文对象的引用,并且能够改变它的状态:

// concrete_state.cpp
#include "concrete_state.h"
#include "context.h"
#include <iostream>

// 红灯
RedLight::RedLight(TrafficLights* context) : m_pContext(context) {}

void RedLight::Handle()
{
    std::cout << "Red Light" << std::endl;
    m_pContext->SetState(new GreenLight(m_pContext));
    delete this;
}

// 绿灯
GreenLight::GreenLight(TrafficLights* context) : m_pContext(context) {}

void GreenLight::Handle()
{
    std::cout << "Green Light" << std::endl;
    m_pContext->SetState(new YellowLight(m_pContext));
    delete this;
}

// 黄灯
YellowLight::YellowLight(TrafficLights* context) : m_pContext(context) {}

void YellowLight::Handle()
{
    std::cout << "Yellow Light" << std::endl;
    m_pContext->SetState(new RedLight(m_pContext));
    delete this;
}

创建客户端

Ready,go!“交通警察”开始工作啦:

// main.cpp
#include "context.h"
#include <iostream>
#include <windows.h>

int main()
{
    TrafficLights tl;

    enum TLState {Red, Green, Yellow};

    TLState state = Red;  // 初始状态为红灯
    int i = 0;  // 总次数
    int seconds;  // 秒数

    while (true) {
        // 表示一个完整的状态流(红灯->绿灯->黄灯)已经完成
        if (i % 3 == 0)
            std::cout << "**********" << "Session " << ((i+1)/3)+1 << "**********" << std::endl;

        // 根据当前状态来设置持续时间,红灯(6秒)、绿灯(4秒)、黄灯(2秒)
        if (state == Red) {
            seconds = 6;
            state = Green;
        } else if (state == Green) {
            seconds = 4;
            state = Yellow;
        } else if (state == Yellow) {
            seconds = 2;
            state = Red;
        }

        // 休眠
        Sleep(seconds * 1000);

        tl.Request();
        i++;
    }

    return 0;
}

输出如下:

*****Session 1*****
Red Light
Green Light
Yellow Light
*****Session 2*****
Red Light
Green Light
Yellow Light
*****Session 3*****
Red Light
Green Light
Yellow Light
*****Session n*****

交通信号灯的状态一般会持续一定时间,这里使用 Sleep() 休眠的方式来实现。当然,现实生活中信号灯的各个状态持续时间较长,为了更快地在各个状态之间进行切换,我们设置了短时间的间隔 - 红灯(6秒)、绿灯(4秒)、黄灯(2秒)。

作者:u011012932 发表于2017/11/27 18:03:07 原文链接
阅读:38 评论:0 查看评论

关于BUG的那些误解

BZOJ1503: [NOI2004]郁闷的出纳员(洛谷P1486)

$
0
0

平衡树

BZOJ题目传送门
洛谷题目传送门

显然用平衡树维护(然而有大佬用了线段树)。插入、查询、删除平衡树都可以支持,但是这里的加减操作有点不常规,我们需要进行转化一下。

新建一个变量表示当前工资下限,那么加工资就变成了减工资下限,减工资就变成了加工资上限。新建节点时需要把工资加上(当前工资下限-原来工资下限),输出时也要减掉。这样就不需要麻烦地打标记。

这里给出Treap的代码:

#include<cstdio>
#include<cstdlib>
#define N 100000
using namespace std;
struct node{
    int w,p,size,rnd,to[2];
}t[N+5];
int n,m,rt,nd,wg,ans;
void rtt(int &x,int fl){
    int s=t[x].to[fl];
    t[x].to[fl]=t[s].to[fl^1];
    t[s].to[fl^1]=x;
    t[s].size=t[x].size;
    t[x].size=t[t[x].to[0]].size+t[t[x].to[1]].size+t[x].p;
    x=s; return;
}
void nsrt(int &x,int w){
    if (!x){
        t[x=++nd].w=w; t[x].size=t[x].p=1;
        t[x].rnd=rand(); return;
    }
    t[x].size++;
    if (t[x].w==w) t[x].p++;
    else{
        int flag=t[x].w<w;
        nsrt(t[x].to[flag],w);
        if (t[x].rnd>t[t[x].to[flag]].rnd) rtt(x,flag);
    }
}
void dlt(int &x,int w){
    if (!x) return;
    if (t[x].w==w){
        if (t[x].p>1) { t[x].p--; t[x].size--; return; }
        if (!(t[x].to[0]*t[x].to[1])) x=t[x].to[0]+t[x].to[1];
        else if (t[t[x].to[0]].rnd<t[t[x].to[1]].rnd) rtt(x,0),dlt(x,w);
        else rtt(x,1),dlt(x,w);
    }
    else{
        t[x].size--;
        if (t[x].w<w) dlt(t[x].to[1],w);
        else dlt(t[x].to[0],w);
    }
}
int srch_nm(int x,int w){
    if (!x) return -1;
    if (t[t[x].to[0]].size>=w)
        return srch_nm(t[x].to[0],w);
    if (t[t[x].to[0]].size+t[x].p>=w)
        return t[x].w-wg+m;
    return srch_nm(t[x].to[1],w-t[t[x].to[0]].size-t[x].p);
}
int srch_frnt(int x,int w){
    if (!x) return -0x7fffffff;
    if (t[x].w<w){
        int k=srch_frnt(t[x].to[1],w);
        if (k!=-0x7fffffff) 
            return k;
        else return t[x].w;
    }
    else return srch_frnt(t[x].to[0],w);
}
int main(){
    scanf("%d%d",&n,&m); wg=m;
    while (n--){
        int x; char s[5];
        scanf("%s%d",&s,&x);
        switch (s[0]){
            case 'I': if (x+wg-m>=wg) nsrt(rt,x+wg-m); break;
            case 'A': wg-=x; break;
            case 'S': wg+=x; break;
            case 'F': x=t[rt].size-x+1,printf("%d\n",srch_nm(rt,x)); break;
        }
        int p=srch_frnt(rt,wg);
        while (p!=-0x7fffffff) 
            dlt(rt,p),p=srch_frnt(rt,wg),ans++;
    }
    return printf("%d\n",ans),0;
}
作者:a1799342217 发表于2017/11/27 19:45:01 原文链接
阅读:12 评论:0 查看评论

Redis对象系统

$
0
0

        在上一节学习Redis中的六种基础数据结构,但在Redis中并没有直接使用以上的数据结构实现键值对数据库,而是基于这些数据结构构建了一个对象系统:字符串对象(String)、列表对象(List)、哈希对象(Hash)、集合对象(Set)和有序集合对象(ZSet)。对于Redis数据库,键总是一个字符串对象,而值则可以是字符串对象、列表对象、哈希对象、集合对象或者有序集合对象中的一种。

        使用对象系统的好处:

(1)在执行命令时,根据对象类型判断一个对象是否可以执行给定的命令;
(2)针对不同的使用场景,为对象设置多种不同的数据结构,从而优化对象在不同场景下的使用效率;
(3)基于对象引用计数技术实现内存的回收;
(4)通过引用计数技术实现对象的共享;

在Redis中每个对象都由一个redisObject结构表示:

/*
 * Redis 对象
 */
typedef struct redisObject {
    // 类型
    unsigned type:4;
    // 编码
    unsigned encoding:4;
    // 对象最后一次被访问的时间
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
    // 引用计数
    int refcount;
    // 指向实际值的指针
    void *ptr;
} robj;

redisObject的类型字段:

redisObject的编码字段:

redisObject不同类型和编码的对象:



一、字符串对象(String)

        由上表可知,String对象的编码可以是int、embstr、raw。根据String对象保存值的不同,其使用的编码也不同:

        1、如果保存的是整数值,并且这个整数值可以用long类型来表示,则整数值会保存在字符串对象结构中的ptr属性里(void * 转换为long),并将字符串对象的编码设置为int。

        2、如果保存的是字符串值,并且这个字符串值长度小于等于39字节,则字符串对象使用embstr编码保存。

        3、如果保存的是字符串值,并且这个字符串值长度大于39字节,则字符串使用raw编码保存。

embstr与raw编码的区别是什么呢?

(a)创建embstr编码字符串内存分配1次,创建raw字符串内存分配2次;
(b)释放embstr编码的字符串调用内存释放函数1次,释放raw编码的字符串调用内存释放函数2次;
(c)embstr编码的字符串对象的所有数据都保存在一块连续的内存里面,可以更好的利用缓存带来的优势;

为什么是39个字节呢? 

embstr是一块连续的内存区域,由redisObject和sdshdr组成。其中redisObject占16个字节,当buf内的字符串长度是39时,sdshdr的大小为8+39+1=48,那一个字节是'\0'。加起来刚好64。(更详细的讲解可以参见知乎@lhcpig的解答

typedef struct redisObject {
    unsigned type:4;
    unsigned encoding:4;
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
    int refcount;
    void *ptr;
} robj;
struct sdshdr {
    unsigned int len;
    unsigned int free;
    char buf[];
};


Window环境下,在本地启动redis-server.exe,然后另启动一个redis-cli.exe。对String对象的操作如下:



二、列表对象(List)

        列表对象的编码可以是ziplist或者linkedlist。ziplist使用压缩列表作为底层实现,linkedlist使用双端链表作为底层实现。根据列表中存放的值不同,编码也有所不同:

        当列表对象所保存的所有字符串元素长度都小于64字节,并且元素数量小于512个,列表使用ziplist编码。不满足这两个条件的列表对象需要使用linkedlist编码。




三、哈希对象(Hash)

        哈希对象的编码可以是ziplist或者是hashtable。ziplist底层使用压缩列表实现,而hashtable底层使用字典实现。根据哈希对象存放的值不同,所使用的编码也不同:

        当哈希对象保存的所有键值对的键和值的字符串长度都小于64字节,并且键值对数量小于512个,哈希对象使用ziplist编码。不满足以上两个条件的哈希对象使用hashtable编码。




四、集合对象(Set)

        集合对象的编码可以是intset或者hashtable。intset底层使用的是整数集合实现,hashtable底层使用字典实现。根据集合对象存放的值不同,集合对象所使用的编码也不相同:

        当集合对象保存的所有元素都是整数值,并且对象保存的元素数量不超过512个,集合对象使用intset编码。不满足以上条件的使用hashtable编码。




五、有序集合对象(ZSet)

        有序集合的编码可以是ziplist或者skiplist。ziplist底层是用压缩列表实现,skiplist使用zset结构作为底层实现。根据有序集合存放的值不同,对象的编码也不同:

        有序集合保存的元素数量小于128个,并且所有元素成员长度都小于64个字节时,有序集合对象使用ziplist编码。不满足以上两个条件的采用skiplist编码。




参考文献

1、http://www.redis.net.cn/tutorial/3506.html

2、《Redis设计与实现》第二版---黄健宏

3、https://github.com/xingzhexiaozhu/redis-3.0-annotated

4、http://www.yiibai.com/redis/redis_strings.html

作者:u012050154 发表于2017/11/27 18:28:36 原文链接
阅读:24 评论:0 查看评论

BZOJ1207(HNOI2004)[打鼹鼠]--最长升

$
0
0

【链接】
bzoj1207

【解题报告】

裸的最长升。

博主太懒,就打O(m^2)的解法了

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=10005;
int n,m,ans,f[maxn];
struct Point
{
    int x,y,t;
}a[maxn];
int Abs(int x) {if (x<0) return (-x); return x;}
int main()
{
    freopen("1207.in","r",stdin);
    freopen("1207.out","w",stdout);
    scanf("%d%d",&n,&m); ans=0;
    for (int i=1; i<=m; i++) scanf("%d%d%d",&a[i].t,&a[i].x,&a[i].y),f[i]=1;
    for (int i=1; i<=m; i++)
     for (int j=1; j<i; j++)
      if (Abs(a[i].x-a[j].x)+Abs(a[i].y-a[j].y)<=a[i].t-a[j].t&&f[j]+1>f[i]) f[i]=f[j]+1;
    for (int i=1; i<=m; i++) ans=max(ans,f[i]);
    printf("%d",ans);
    return 0;
}
作者:CHNWJD 发表于2017/11/27 20:08:28 原文链接
阅读:42 评论:0 查看评论

[Splay]BZOJ 1208——[HNOI2004]宠物收养所

$
0
0

题目描述

最近,阿Q开了一间宠物收养所。收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物。每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领养的宠物的特点值a(a是一个正整数,a<2^31),而他也给每个处在收养所的宠物一个特点值。这样他就能够很方便的处理整个领养宠物的过程了,宠物收养所总是会有两种情况发生:被遗弃的宠物过多或者是想要收养宠物的人太多,而宠物太少。 1. 被遗弃的宠物过多时,假若到来一个领养者,这个领养者希望领养的宠物的特点值为a,那么它将会领养一只目前未被领养的宠物中特点值最接近a的一只宠物。(任何两只宠物的特点值都不可能是相同的,任何两个领养者的希望领养宠物的特点值也不可能是一样的)如果有两只满足要求的宠物,即存在两只宠物他们的特点值分别为a-b和a+b,那么领养者将会领养特点值为a-b的那只宠物。 2. 收养宠物的人过多,假若到来一只被收养的宠物,那么哪个领养者能够领养它呢?能够领养它的领养者,是那个希望被领养宠物的特点值最接近该宠物特点值的领养者,如果该宠物的特点值为a,存在两个领养者他们希望领养宠物的特点值分别为a-b和a+b,那么特点值为a-b的那个领养者将成功领养该宠物。 一个领养者领养了一个特点值为a的宠物,而它本身希望领养的宠物的特点值为b,那么这个领养者的不满意程度为abs(a-b)。【任务描述】你得到了一年当中,领养者和被收养宠物到来收养所的情况,希望你计算所有收养了宠物的领养者的不满意程度的总和。这一年初始时,收养所里面既没有宠物,也没有领养者。

解题思路

直接上splay。

介绍一下删除和插入操作。

插入就按照大小遍历平衡树,在某个叶子节点放下这个节点,为了使树更平衡要再伸展一次。

删除操作就直接找到右边最小节点,把这个节点的左节点给左边的树,然后根给右儿子。

这里的伸展操作是将某个值得节点旋转到根,除了cmp没有什么区别。

#include<cstdio>
using namespace std;
const int maxn=100005,tt=1000000;
struct jz{
    int x;
    jz* son[2];
    int cmp(int k){if (k<x) return 0;if (k==x) return -1;else return 1;}
}a[maxn],*null=a,*len=null,*ro=null;
inline int _read(){
    int num=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();
    return num;
}
int n,now,ans,t1,t2;
jz* newnode(int x){
    len++;len->x=x;
    len->son[0]=len->son[1]=null;
    return len;
}
void turn(jz* &k,int d){
    jz* t=k->son[d];k->son[d]=t->son[d^1];t->son[d^1]=k;
    k=t;
}
void splay(jz* &k,int x){
    int d1=k->cmp(x);
    if (d1!=-1){
        jz* p=k->son[d1];int d2=p->cmp(x);
        if (d2!=-1){
            splay(p->son[d2],x);
            if (d2==d1) turn(k,d1),turn(k,d1);
            else turn(k->son[d1],d2),turn(k,d1);
        }else turn(k,d1);
    }
}
void Insert(jz* &k,int x){
    if (k==null) k=newnode(x),splay(ro,x);else
    {if (x<k->x) Insert(k->son[0],x);else Insert(k->son[1],x);}
}
void ask1(jz* k,int x){
    if (k==null) return;
    if (k->x<=x){t1=k->x;ask1(k->son[1],x);}
    else ask1(k->son[0],x);
}
void ask2(jz* k,int x){
    if (k==null) return;
    if (k->x>=x){t2=k->x;ask2(k->son[0],x);}
    else ask2(k->son[1],x);
}
void del(int x){
    splay(ro,x);
    if (ro->son[0]==null||ro->son[1]==null){
        if (ro->son[0]==null) ro=ro->son[1];
        else                  ro=ro->son[0];
    }else{
        jz* k=ro->son[1];
        while(k->son[0]!=null) k=k->son[0];
        k->son[0]=ro->son[0];ro=ro->son[1];
    }
}
int main(){
    freopen("exam.in","r",stdin);
    freopen("exam.out","w",stdout);
    n=_read();
    for (int i=1;i<=n;i++){
        int t=_read(),x=_read();
        if (ro==null) now=t,Insert(ro,x);else
        if (t==now) Insert(ro,x);else{
            t1=t2=-1;ask1(ro,x);ask2(ro,x);
            if (t2==-1||(t1!=-1&&x-t1<=t2-x)) del(t1),ans=(ans+x-t1)%tt;
            else                              del(t2),ans=(ans+t2-x)%tt;
        }
    }
    printf("%d\n",ans);
    return 0;
}
作者:CHN_JZ 发表于2017/11/27 20:20:42 原文链接
阅读:51 评论:0 查看评论

Python3 正则相关

$
0
0

一、简述

        正则表达式的作用是检查一个字符串是否与某种模式匹配。compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。
        re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。

二、常见的函数


  • re.match函数
       re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。匹配成功re.match方法返回一个匹配的对象。

    语法:    re.match(pattern, string, flags=0)
    参数说明:
  • pattern 匹配的正则表达式
  • string  要匹配的字符串。
  • flags   标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

  • 使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
    • group(num=0)    匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
    • groups( )    返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
  • 区别:
    • re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

三、检索与模式替换

  • re模块中由 re.sub 用于替换字符串中的匹配项 。

re.sub(pattern,repl,string,count=0)
参数:
pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
   count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。


四、正则表达式相关概念


  • 表达式修饰符 

                      
  • 正则表达式模式
    • 由于正则表达式通常都包含反斜杠,故最好使用原始字符串,模式元素(如 r'\t',等价于 \\t )匹配相应的特殊字符。
                                  
                    
 
                   
   
  • 正则表达式例子
                   
    
                                


作者:smilejiasmile 发表于2017/11/27 20:30:09 原文链接
阅读:44 评论:0 查看评论

BZOJ1800(Ahoi2009)[fly 飞行棋]--傻逼几何

$
0
0

【链接】
bzoj1800

【解题报告】

其实就是统计两条弧之间从左走和从右走长度一样的方案数。

n这么小,乱搞就好了

#include<cstdio>
using namespace std;
const int maxn=25;
int n,ans,sum,a[maxn];
int main()
{
    freopen("1800.in","r",stdin);
    freopen("1800.out","w",stdout);
    scanf("%d",&n); sum=ans=0;
    for (int i=1; i<=n; i++) scanf("%d",&a[i]),sum+=a[i];
    for (int i=1; i<n; i++)
    {
        int now=a[i];
        for (int j=i+1; j<=n; j++)
        {
            if (sum-now==now) {ans++; break;}
            if (sum-now<now) break;
            now+=a[j];
        }
    }
    printf("%d",ans*(ans-1)/2);
    return 0;
}
作者:CHNWJD 发表于2017/11/27 20:38:12 原文链接
阅读:29 评论:0 查看评论

442. Find All Duplicates in an Array。

$
0
0

Given an array of integers, 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once.

Find all the elements that appear twice in this array.

Could you do it without extra space and in O(n) runtime?

Example:

Input:
[4,3,2,7,8,2,3,1]

Output:
[2,3]


题中说给一个整型数组,数组的范围为:1 <= a[i] <= n (这个n,就是数组的长度),然后数组中有一些元素出现两次,有一些出现一次,让我们找出出现两次的元素。

比较简单的一种做法就是用一个set,遍历数组并与set中的元素进行比较,如果set中没有该数组元素,就将数组元素放进去,如果有了就说明重复了,将其加到数组中最后返回即可。

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        unordered_set<int> target;
        vector<int> res;

        for(int i=0;i<nums.size();i++) {
            if(target.find(nums[i]) == target.end()) {//如果此刻该set中不存在该数字,则存放一个数字
                target.insert(nums[i]);
            } else {
                res.push_back(nums[i]);
            }
        }
        return res;
    }
};

另一种做法就是利用题中的隐含条件: 1 <= a[i] <= n (这个n,就是数组的长度),从这个条件中我们可以得到数组中的任何一个数字都要比数组的长度小或等于。

比如例子中的数组长度为8,那么数组中的元素最大值就是8。利用这一点我们可以换个思维来考虑,如果说数组中的任何元素都要小于或者等于数组的长度,那么数组中的任何元素减去1之后得到的数字正好在数组的下标之间,减去1之后,数组中的元素范围就成了:0<= a[i] <= n-1,这代表这减去1之后的数字,如果用来做原来数组的下标的话是不可能溢出的。所以我们可以遍历原来的数组,分别取出每个元素并减1,然后用得到的数字作为下标去数组中找到对应的位置,如果这个元素在数组中只出现一次,那么该元素对应的下标就只会被访问一次(除了循环遍历的那一次),相反如果这个元素在数组中出现了两次,那么该元素对应的下标就会被访问两次。

例如例子中的第一个元素:4,减去1之后对应的3作为下标,这时去访问数组中下标为3的位置,而且只会访问一次。如果是例子中的第二个数:3,减去1之后对应的2作为下标,这时去访问数组中下标为2的位置,并且在例子的七个元素也是3,减去1之后也会去访问数组中下标为2的位置。那么下标为2的位置就会被访问两次。

我么可以利用这个特点来解题,在遍历的时候取出每个元素减去1之后,拿着这个数字作为下标去数组中找到对应的位置,并且将对应位置中的数字变为负数,这样如果没有重复的话,这个负数是不会被其他下标访问到的,如果有重复的话第二次访问就会发现这个位置对应元素为负数,此刻就能说明重复了。但是有一点就是如果将数组中的元素变成负数的话,就不能正常遍历了,毕竟负数不能做为数组下标,所以此刻就可以将元素取绝对值。

举个例子:数组 [1,3,1] ,依次遍历:
第一次取出:1,减去1之后得到0,将0作为下标去访问数组中的元素,数组中下标为0的元素为1,我们将其变为负数:-1.

第二次取出:3,减去1之后得到2,将2作为下标去访问数组中的元素,数组中下标为2的元素为1,我们将其变为负数:-1.

第三次取出:1(取绝对值),减去1之后得到0,将0作为下标去访问数组中的元素,数组中下标为0的元素,发现此刻的元素为负数:-1,说明这个之前就被访问过了,说明此刻这个元素已经有了重复值。


class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        vector<int> res;
        for(int n: nums) {
            n = abs(n);
            if(nums[n-1] > 0) {
                nums[n-1] = -nums[n-1];
            } else {
                res.push_back(n);
            }
        }
        return res;
    }
};
作者:Leafage_M 发表于2017/11/27 21:03:43 原文链接
阅读:18 评论:0 查看评论

刷题笔记:牛客字符串专项练习2

$
0
0

题目:
设S为一个长度为n的字符串,其中的字符各不相同,则S中的互异的非平凡子串(非空且不同于S本身)的个数为()

A.2n-1
B.n²
C.(n²/2)+(n/2)
D.(n²/2)+(n/2)-1
E.(n²/2)-(n/2)-1
F.其他情况

答案:D
知识点:互异的非平凡子串

解析:
非平凡子串即非空且不同于S本身的子串。对于长度为n的字符串,长度为1的互异的子串为n个,长度为2的互异的子串为n-1个,以此类推,长度为n的互异的子串为1个,则总的互异的子串数为n+(n-1)+……+1 = n*(n+1)/2。则互异的非平凡子串数为n*(n+1)/2-1=(n²/2)+(n/2)-1。

作者:lin453701006 发表于2017/11/27 21:09:08 原文链接
阅读:23 评论:0 查看评论
Viewing all 35570 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>